Skip to content

Commit 82852c2

Browse files
authored
Refactored async initialization logic for Mixpanel, Grafana, and Launch Darkly (#624)
1 parent 20d2c53 commit 82852c2

File tree

91 files changed

+1744
-1495
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+1744
-1495
lines changed

.changeset/dirty-humans-rule.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@replayio/cypress": patch
3+
"@replayio/jest": patch
4+
"@replayio/playwright": patch
5+
"@replayio/puppeteer": patch
6+
"replayio": patch
7+
---
8+
9+
Improve async initialization and teardown logic

packages/cypress/src/fixture.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { logger } from "@replay-cli/shared/logger";
1+
import { logInfo } from "@replay-cli/shared/logger";
22
import { writeFileSync, appendFileSync, mkdirSync } from "fs";
33
import path from "path";
44

@@ -14,11 +14,11 @@ function getFixtureFile() {
1414
}
1515

1616
export function initFixtureFile() {
17-
logger.info("InitFixtureFile:Started", {
17+
logInfo("InitFixtureFile:Started", {
1818
updateFixture: process.env.REPLAY_CYPRESS_UPDATE_FIXTURE,
1919
});
2020
if (process.env.REPLAY_CYPRESS_UPDATE_FIXTURE) {
21-
logger.info("InitFixtureFile:FixtureFile", { fixtureFile: getFixtureFile() });
21+
logInfo("InitFixtureFile:FixtureFile", { fixtureFile: getFixtureFile() });
2222
try {
2323
mkdirSync(path.dirname(getFixtureFile()), { recursive: true });
2424
writeFileSync(getFixtureFile(), "");

packages/cypress/src/index.ts

+29-34
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/// <reference types="cypress" />
22

3-
import { logger } from "@replay-cli/shared/logger";
4-
import { mixpanelAPI } from "@replay-cli/shared/mixpanel/mixpanelAPI";
3+
import { logError, logInfo } from "@replay-cli/shared/logger";
4+
import { trackEvent } from "@replay-cli/shared/mixpanelClient";
5+
import { waitForExitTasks } from "@replay-cli/shared/process/waitForExitTasks";
56
import { getRuntimePath } from "@replay-cli/shared/runtime/getRuntimePath";
6-
import { setUserAgent } from "@replay-cli/shared/userAgent";
7+
import { initializeSession } from "@replay-cli/shared/session/initializeSession";
78
import { RecordingEntry, initMetadataFile, warn } from "@replayio/test-utils";
89
import chalk from "chalk";
910
import path from "path";
@@ -71,7 +72,7 @@ function updateReporters(
7172
config: Cypress.PluginConfigOptions
7273
) {
7374
const { reporter, reporterOptions } = config;
74-
logger.info("UpdateReporters:Started", { reporter, reporterOptions });
75+
logInfo("UpdateReporters:Started", { reporter, reporterOptions });
7576
if (reporter !== "junit") {
7677
return;
7778
}
@@ -96,11 +97,11 @@ function onBeforeBrowserLaunch(
9697
browser: Cypress.Browser,
9798
launchOptions: Cypress.BeforeBrowserLaunchOptions
9899
) {
99-
logger.info("OnBeforeBrowserLaunch:Started", { browser, launchOptions });
100+
logInfo("OnBeforeBrowserLaunch:Started", { browser, launchOptions });
100101
assertReporter(cypressReporter);
101102
cypressReporter.onLaunchBrowser(browser.family);
102103

103-
logger.info("OnBeforeBrowserLaunch:BrowserLaunching", { family: browser.family });
104+
logInfo("OnBeforeBrowserLaunch:BrowserLaunching", { family: browser.family });
104105

105106
const config = cypressReporter.config;
106107
if (browser.name !== "electron" && config.version && semver.gte(config.version, "10.9.0")) {
@@ -121,7 +122,7 @@ function onBeforeBrowserLaunch(
121122
...cypressReporter.getExtraEnv(),
122123
};
123124

124-
logger.info("OnBeforeBrowserLaunch:BrowserEnvironment", { replayEnv });
125+
logInfo("OnBeforeBrowserLaunch:BrowserEnvironment", { replayEnv });
125126

126127
launchOptions.env = env;
127128
}
@@ -158,8 +159,8 @@ async function onAfterRun() {
158159
});
159160

160161
if (missingSteps) {
161-
logger.error("OnAfterRun:AfterRunMissingSteps", { missingSteps });
162-
mixpanelAPI.trackEvent("warning.missing-steps");
162+
logError("OnAfterRun:AfterRunMissingSteps", { missingSteps });
163+
trackEvent("warning.missing-steps");
163164
loudWarning(
164165
"Your tests completed but our plugin did not receive any command events.",
165166
"",
@@ -169,35 +170,35 @@ async function onAfterRun() {
169170
);
170171
}
171172

172-
await logger.close().catch(() => {});
173+
await waitForExitTasks();
173174
}
174175

175176
function onBeforeSpec(spec: Cypress.Spec) {
176-
logger.info("OnBeforeSpec:Started", { spec: spec.relative });
177+
logInfo("OnBeforeSpec:Started", { spec: spec.relative });
177178
assertReporter(cypressReporter);
178179
cypressReporter.onBeforeSpec(spec);
179180
}
180181

181182
function onAfterSpec(spec: Cypress.Spec, result: CypressCommandLine.RunResult) {
182-
logger.info("OnAfterSpec:Started", { spec: spec.relative });
183+
logInfo("OnAfterSpec:Started", { spec: spec.relative });
183184
assertReporter(cypressReporter);
184185
return cypressReporter.onAfterSpec(spec, result);
185186
}
186187

187188
function onReplayTask(value: any) {
188-
logger.info("OnReplayTask:Started", { value });
189+
logInfo("OnReplayTask:Started", { value });
189190
assertReporter(cypressReporter);
190191
const reporter = cypressReporter;
191192

192193
if (!Array.isArray(value)) return;
193194

194195
value.forEach(v => {
195196
if (isStepEvent(v)) {
196-
logger.info("OnReplayTask:ReplayTaskEvent", { event: v });
197+
logInfo("OnReplayTask:ReplayTaskEvent", { event: v });
197198
reporter.addStep(v);
198199
} else {
199-
logger.error("OnReplayTask:ReplayTaskUnexpectedPayload", { payload: v });
200-
mixpanelAPI.trackEvent("error.replay-task-unexpected-payload", { payload: v });
200+
logError("OnReplayTask:ReplayTaskUnexpectedPayload", { payload: v });
201+
trackEvent("error.replay-task-unexpected-payload", { payload: v });
201202
}
202203
});
203204

@@ -261,14 +262,8 @@ const plugin = (
261262
config: Cypress.PluginConfigOptions,
262263
options: PluginOptions = {}
263264
) => {
264-
setUserAgent(`${packageName}/${packageVersion}`);
265-
266-
const accessToken = getAuthKey(config);
267-
268-
logger.initialize(packageName, packageVersion);
269-
logger.identify(accessToken);
270-
mixpanelAPI.initialize({
271-
accessToken,
265+
initializeSession({
266+
accessToken: getAuthKey(config),
272267
packageName,
273268
packageVersion,
274269
});
@@ -277,15 +272,15 @@ const plugin = (
277272

278273
const portPromise = createServer().then(({ server: wss, port }) => {
279274
wss.on("connection", function connection(ws) {
280-
logger.info("CypressPlugin:WebSocketConnected");
275+
logInfo("CypressPlugin:WebSocketConnected");
281276

282277
ws.on("close", () => {
283-
logger.info("CypressPlugin:WebSocketClosed");
278+
logInfo("CypressPlugin:WebSocketClosed");
284279
});
285280

286281
ws.on("error", error => {
287-
logger.error("CypressPlugin:WebSocketError", { error });
288-
mixpanelAPI.trackEvent("error.websocket-error", { error });
282+
logError("CypressPlugin:WebSocketError", { error });
283+
trackEvent("error.websocket-error", { error });
289284
warn("WebSocket error", error);
290285
});
291286

@@ -295,8 +290,8 @@ const plugin = (
295290
const obj = JSON.parse(payload) as { events: StepEvent[] };
296291
onReplayTask(obj.events);
297292
} catch (error) {
298-
logger.error("CypressPlugin:WebSocketMessageError", { error });
299-
mixpanelAPI.trackEvent("error.websocket-message-error", { error });
293+
logError("CypressPlugin:WebSocketMessageError", { error });
294+
trackEvent("error.websocket-message-error", { error });
300295
warn("Error parsing message from test", error);
301296
}
302297
});
@@ -324,7 +319,7 @@ const plugin = (
324319
[CONNECT_TASK_NAME]: async value => {
325320
const port = await portPromise;
326321

327-
logger.info("CypressPlugin:ConnectedToServer", { port });
322+
logInfo("CypressPlugin:ConnectedToServer", { port });
328323
return { port };
329324
},
330325
});
@@ -344,14 +339,14 @@ const plugin = (
344339
if (config.isTextTerminal) {
345340
config.env.NO_COMMAND_LOG =
346341
process.env.CYPRESS_NO_COMMAND_LOG ?? config.env.NO_COMMAND_LOG ?? 1;
347-
logger.info("CypressPlugin:CommandLogEnabled", {
342+
logInfo("CypressPlugin:CommandLogEnabled", {
348343
noCommandLog: config.env.NO_COMMAND_LOG,
349344
});
350345
}
351346

352347
const chromiumPath = getRuntimePath();
353348
if (chromiumPath) {
354-
logger.info("CypressPlugin:AddedChromium", { chromiumPath });
349+
logInfo("CypressPlugin:AddedChromium", { chromiumPath });
355350
config.browsers = config.browsers.concat({
356351
name: "replay-chromium",
357352
channel: "stable",
@@ -364,7 +359,7 @@ const plugin = (
364359
isHeadless: false,
365360
});
366361
} else {
367-
logger.info("CypressPlugin:ReplayChromiumNotSupported", {
362+
logInfo("CypressPlugin:ReplayChromiumNotSupported", {
368363
platform: process.platform,
369364
chromiumPath,
370365
});

packages/cypress/src/junit.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { logger } from "@replay-cli/shared/logger";
1+
import { logDebug, logError, logInfo } from "@replay-cli/shared/logger";
22
import { warn } from "@replayio/test-utils";
33
import { RecordingEntry } from "@replayio/test-utils";
44
import fs, { readFileSync, writeFileSync } from "fs";
@@ -14,15 +14,15 @@ function readXmlFile(path: string) {
1414
}
1515

1616
try {
17-
logger.debug("ReadXmlFile:Started", { path });
17+
logDebug("ReadXmlFile:Started", { path });
1818
const contents = readFileSync(path, "utf-8");
19-
logger.info("ReadXmlFile:FileInfo", { bytes: contents.length, path });
19+
logInfo("ReadXmlFile:FileInfo", { bytes: contents.length, path });
2020
const dom = xml(contents, { setPos: false, noChildNodes: ["?xml"] });
2121
gFileCache.set(path, dom);
2222

2323
return dom;
2424
} catch (e) {
25-
logger.error("ReadXmlFile:Failed", { path, error: e });
25+
logError("ReadXmlFile:Failed", { path, error: e });
2626
warn("[junit] Failed to read and parse reporter file", e);
2727
}
2828
}
@@ -43,7 +43,7 @@ function writeOutputFile(dom: (string | INode)[], outputFile: string) {
4343
.join("\n");
4444
writeFileSync(outputFile, updatedContents, "utf-8");
4545
} catch (e) {
46-
logger.error("WriteOutputFile:Failed", { outputFile, error: e });
46+
logError("WriteOutputFile:Failed", { outputFile, error: e });
4747
warn("[junit] Failed to update reporter file", e);
4848
}
4949
}
@@ -105,7 +105,7 @@ function addReplayLinkProperty(node: INode, replayUrls: string[]) {
105105
)
106106
);
107107
} catch (e) {
108-
logger.error("AddReplayLinkProperty:Failed", { error: e });
108+
logError("AddReplayLinkProperty:Failed", { error: e });
109109
}
110110
}
111111

@@ -116,13 +116,13 @@ function escapeForXml(content: string) {
116116
function appendReplayUrlsToFailureNodes(node: INode, replayUrls: string[]) {
117117
try {
118118
const failures = findDescendentsByTagName(node, "failure");
119-
logger.info("AppendReplayUrlsToFailures:Started", {
119+
logInfo("AppendReplayUrlsToFailures:Started", {
120120
failures: failures.length,
121121
replayUrls,
122122
});
123123
failures.forEach(failure => {
124124
if (typeof failure.children[0] !== "string") {
125-
logger.info("AppendReplayUrlsToFailures:FailureNodeNotString", { failure });
125+
logInfo("AppendReplayUrlsToFailures:FailureNodeNotString", { failure });
126126
return;
127127
}
128128

@@ -133,7 +133,7 @@ function appendReplayUrlsToFailureNodes(node: INode, replayUrls: string[]) {
133133
failure.children[0] = escapeForXml(output);
134134
});
135135
} catch (e) {
136-
logger.error("AppendReplayUrlsToFailures:Failed", { error: e });
136+
logError("AppendReplayUrlsToFailures:Failed", { error: e });
137137
}
138138
}
139139

@@ -150,7 +150,7 @@ function findOutputFileForSpec(specRelativePath: string, xmlFiles: string[]) {
150150
const rootSuite = getRootSuite(dom);
151151

152152
if (!rootSuite || !testSuites) {
153-
logger.error("FindOutputFileForSpec:FailedToFindRootSuite", { dom });
153+
logError("FindOutputFileForSpec:FailedToFindRootSuite", { dom });
154154
continue;
155155
}
156156

@@ -181,15 +181,15 @@ export function updateJUnitReports(
181181
mochaFile?: string
182182
) {
183183
try {
184-
logger.info("UpdateJUnitReports:Started", {
184+
logInfo("UpdateJUnitReports:Started", {
185185
specRelativePath,
186186
recordings: recordings.map(r => r.id),
187187
projectBase,
188188
mochaFile,
189189
});
190190

191191
if (mochaFile && typeof mochaFile !== "string") {
192-
logger.error("UpdateJUnitReports:InvalidMochaFile", { mochaFile });
192+
logError("UpdateJUnitReports:InvalidMochaFile", { mochaFile });
193193
warn(
194194
"Unsupported reporterOptions configuration",
195195
new Error("Expected string for mocha file but received " + typeof mochaFile)
@@ -205,7 +205,7 @@ export function updateJUnitReports(
205205
throw new Error(`Failed to find JUnit reporter output file`);
206206
}
207207

208-
logger.info("UpdateJUnitReports:FoundRootSuite", { specRelativePath });
208+
logInfo("UpdateJUnitReports:FoundRootSuite", { specRelativePath });
209209

210210
const testSuites = getTestSuitesNode(dom);
211211
const rootSuite = getRootSuite(dom);
@@ -222,7 +222,7 @@ export function updateJUnitReports(
222222

223223
writeOutputFile(dom, xmlFile);
224224
} catch (e) {
225-
logger.error("UpdateJUnitReports:Failed", { specRelativePath, error: e });
225+
logError("UpdateJUnitReports:Failed", { specRelativePath, error: e });
226226
warn(`[junit] Unexpected reporter error for ${specRelativePath}`, e);
227227
}
228228
}

packages/cypress/src/reporter.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
type UploadOptions,
1010
} from "@replayio/test-utils";
1111

12-
import { logger } from "@replay-cli/shared/logger";
12+
import { logInfo } from "@replay-cli/shared/logger";
1313
import { Errors } from "./error";
1414
import { PluginFeature, getFeatures, isFeatureEnabled } from "./features";
1515
import { appendToFixtureFile, initFixtureFile } from "./fixture";
@@ -76,7 +76,7 @@ class CypressReporter {
7676
);
7777

7878
this.featureOptions = process.env.CYPRESS_REPLAY_PLUGIN_FEATURES;
79-
logger.info("CypressReporter:InitializedWithFeatures", {
79+
logInfo("CypressReporter:InitializedWithFeatures", {
8080
features: getFeatures(this.featureOptions),
8181
});
8282
}
@@ -88,7 +88,7 @@ class CypressReporter {
8888
async authenticate(apiKey: string) {
8989
this.reporter.setApiKey(apiKey);
9090
const { env } = await fetchWorkspaceConfig(apiKey);
91-
logger.info("Authenticate:ExtraEnv", env);
91+
logInfo("Authenticate:ExtraEnv", env);
9292
this._extraEnv = env;
9393
this.reporter.setDiagnosticMetadata(env);
9494
}
@@ -116,13 +116,13 @@ class CypressReporter {
116116
let currentCount = this.getStepCount();
117117
const startTime = Date.now();
118118
while (Date.now() < startTime + MAX_WAIT) {
119-
logger.info("WaitingForStableStepCount:Count", { currentCount });
119+
logInfo("WaitingForStableStepCount:Count", { currentCount });
120120
const previousCount = currentCount;
121121
await new Promise(resolve => setTimeout(resolve, 250));
122122
currentCount = this.getStepCount();
123123

124124
if (previousCount === currentCount) {
125-
logger.info("WaitingForStableStepCount:BreakCondition", {
125+
logInfo("WaitingForStableStepCount:BreakCondition", {
126126
currentCount,
127127
duration: Date.now() - startTime,
128128
});
@@ -200,7 +200,7 @@ class CypressReporter {
200200
result.tests.length === 0
201201
) {
202202
const msg = "No test results found for spec " + spec.relative;
203-
logger.info("GetTestResults:NoTestResults", { spec: spec.relative });
203+
logInfo("GetTestResults:NoTestResults", { spec: spec.relative });
204204
this.reporter.addError(new ReporterError(Errors.NoTestResults, msg, spec.relative));
205205

206206
return [

0 commit comments

Comments
 (0)