Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored async initialization logic for Mixpanel, Grafana, and Launch Darkly #624

Merged
merged 10 commits into from
Jul 15, 2024
9 changes: 9 additions & 0 deletions .changeset/dirty-humans-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@replayio/cypress": patch
"@replayio/jest": patch
"@replayio/playwright": patch
"@replayio/puppeteer": patch
"replayio": patch
---

Improve async initialization and teardown logic
2 changes: 1 addition & 1 deletion .yarn/releases/yarn-4.1.1.cjs
bvaughn marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions packages/cypress/src/fixture.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { logger } from "@replay-cli/shared/logger";
import { logInfo } from "@replay-cli/shared/logger";
import { writeFileSync, appendFileSync, mkdirSync } from "fs";
import path from "path";

Expand All @@ -14,11 +14,11 @@ function getFixtureFile() {
}

export function initFixtureFile() {
logger.info("InitFixtureFile:Started", {
logInfo("InitFixtureFile:Started", {
updateFixture: process.env.REPLAY_CYPRESS_UPDATE_FIXTURE,
});
if (process.env.REPLAY_CYPRESS_UPDATE_FIXTURE) {
logger.info("InitFixtureFile:FixtureFile", { fixtureFile: getFixtureFile() });
logInfo("InitFixtureFile:FixtureFile", { fixtureFile: getFixtureFile() });
try {
mkdirSync(path.dirname(getFixtureFile()), { recursive: true });
writeFileSync(getFixtureFile(), "");
Expand Down
63 changes: 29 additions & 34 deletions packages/cypress/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/// <reference types="cypress" />

import { logger } from "@replay-cli/shared/logger";
import { mixpanelAPI } from "@replay-cli/shared/mixpanel/mixpanelAPI";
import { logError, logInfo } from "@replay-cli/shared/logger";
import { trackEvent } from "@replay-cli/shared/mixpanelClient";
import { waitForExitTasks } from "@replay-cli/shared/process/waitForExitTasks";
import { getRuntimePath } from "@replay-cli/shared/runtime/getRuntimePath";
import { setUserAgent } from "@replay-cli/shared/userAgent";
import { initializeSession } from "@replay-cli/shared/session/initializeSession";
import { RecordingEntry, initMetadataFile, warn } from "@replayio/test-utils";
import chalk from "chalk";
import path from "path";
Expand Down Expand Up @@ -71,7 +72,7 @@ function updateReporters(
config: Cypress.PluginConfigOptions
) {
const { reporter, reporterOptions } = config;
logger.info("UpdateReporters:Started", { reporter, reporterOptions });
logInfo("UpdateReporters:Started", { reporter, reporterOptions });
if (reporter !== "junit") {
return;
}
Expand All @@ -96,11 +97,11 @@ function onBeforeBrowserLaunch(
browser: Cypress.Browser,
launchOptions: Cypress.BeforeBrowserLaunchOptions
) {
logger.info("OnBeforeBrowserLaunch:Started", { browser, launchOptions });
logInfo("OnBeforeBrowserLaunch:Started", { browser, launchOptions });
assertReporter(cypressReporter);
cypressReporter.onLaunchBrowser(browser.family);

logger.info("OnBeforeBrowserLaunch:BrowserLaunching", { family: browser.family });
logInfo("OnBeforeBrowserLaunch:BrowserLaunching", { family: browser.family });

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

logger.info("OnBeforeBrowserLaunch:BrowserEnvironment", { replayEnv });
logInfo("OnBeforeBrowserLaunch:BrowserEnvironment", { replayEnv });

launchOptions.env = env;
}
Expand Down Expand Up @@ -158,8 +159,8 @@ async function onAfterRun() {
});

if (missingSteps) {
logger.error("OnAfterRun:AfterRunMissingSteps", { missingSteps });
mixpanelAPI.trackEvent("warning.missing-steps");
logError("OnAfterRun:AfterRunMissingSteps", { missingSteps });
trackEvent("warning.missing-steps");
loudWarning(
"Your tests completed but our plugin did not receive any command events.",
"",
Expand All @@ -169,35 +170,35 @@ async function onAfterRun() {
);
}

await logger.close().catch(() => {});
await waitForExitTasks();
}

function onBeforeSpec(spec: Cypress.Spec) {
logger.info("OnBeforeSpec:Started", { spec: spec.relative });
logInfo("OnBeforeSpec:Started", { spec: spec.relative });
assertReporter(cypressReporter);
cypressReporter.onBeforeSpec(spec);
}

function onAfterSpec(spec: Cypress.Spec, result: CypressCommandLine.RunResult) {
logger.info("OnAfterSpec:Started", { spec: spec.relative });
logInfo("OnAfterSpec:Started", { spec: spec.relative });
assertReporter(cypressReporter);
return cypressReporter.onAfterSpec(spec, result);
}

function onReplayTask(value: any) {
logger.info("OnReplayTask:Started", { value });
logInfo("OnReplayTask:Started", { value });
assertReporter(cypressReporter);
const reporter = cypressReporter;

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

value.forEach(v => {
if (isStepEvent(v)) {
logger.info("OnReplayTask:ReplayTaskEvent", { event: v });
logInfo("OnReplayTask:ReplayTaskEvent", { event: v });
reporter.addStep(v);
} else {
logger.error("OnReplayTask:ReplayTaskUnexpectedPayload", { payload: v });
mixpanelAPI.trackEvent("error.replay-task-unexpected-payload", { payload: v });
logError("OnReplayTask:ReplayTaskUnexpectedPayload", { payload: v });
trackEvent("error.replay-task-unexpected-payload", { payload: v });
}
});

Expand Down Expand Up @@ -261,14 +262,8 @@ const plugin = (
config: Cypress.PluginConfigOptions,
options: PluginOptions = {}
) => {
setUserAgent(`${packageName}/${packageVersion}`);

const accessToken = getAuthKey(config);

logger.initialize(packageName, packageVersion);
logger.identify(accessToken);
mixpanelAPI.initialize({
accessToken,
initializeSession({
accessToken: getAuthKey(config),
packageName,
packageVersion,
});
Expand All @@ -277,15 +272,15 @@ const plugin = (

const portPromise = createServer().then(({ server: wss, port }) => {
wss.on("connection", function connection(ws) {
logger.info("CypressPlugin:WebSocketConnected");
logInfo("CypressPlugin:WebSocketConnected");

ws.on("close", () => {
logger.info("CypressPlugin:WebSocketClosed");
logInfo("CypressPlugin:WebSocketClosed");
});

ws.on("error", error => {
logger.error("CypressPlugin:WebSocketError", { error });
mixpanelAPI.trackEvent("error.websocket-error", { error });
logError("CypressPlugin:WebSocketError", { error });
trackEvent("error.websocket-error", { error });
warn("WebSocket error", error);
});

Expand All @@ -295,8 +290,8 @@ const plugin = (
const obj = JSON.parse(payload) as { events: StepEvent[] };
onReplayTask(obj.events);
} catch (error) {
logger.error("CypressPlugin:WebSocketMessageError", { error });
mixpanelAPI.trackEvent("error.websocket-message-error", { error });
logError("CypressPlugin:WebSocketMessageError", { error });
trackEvent("error.websocket-message-error", { error });
warn("Error parsing message from test", error);
}
});
Expand Down Expand Up @@ -324,7 +319,7 @@ const plugin = (
[CONNECT_TASK_NAME]: async value => {
const port = await portPromise;

logger.info("CypressPlugin:ConnectedToServer", { port });
logInfo("CypressPlugin:ConnectedToServer", { port });
return { port };
},
});
Expand All @@ -344,14 +339,14 @@ const plugin = (
if (config.isTextTerminal) {
config.env.NO_COMMAND_LOG =
process.env.CYPRESS_NO_COMMAND_LOG ?? config.env.NO_COMMAND_LOG ?? 1;
logger.info("CypressPlugin:CommandLogEnabled", {
logInfo("CypressPlugin:CommandLogEnabled", {
noCommandLog: config.env.NO_COMMAND_LOG,
});
}

const chromiumPath = getRuntimePath();
if (chromiumPath) {
logger.info("CypressPlugin:AddedChromium", { chromiumPath });
logInfo("CypressPlugin:AddedChromium", { chromiumPath });
config.browsers = config.browsers.concat({
name: "replay-chromium",
channel: "stable",
Expand All @@ -364,7 +359,7 @@ const plugin = (
isHeadless: false,
});
} else {
logger.info("CypressPlugin:ReplayChromiumNotSupported", {
logInfo("CypressPlugin:ReplayChromiumNotSupported", {
platform: process.platform,
chromiumPath,
});
Expand Down
28 changes: 14 additions & 14 deletions packages/cypress/src/junit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { logger } from "@replay-cli/shared/logger";
import { logDebug, logError, logInfo } from "@replay-cli/shared/logger";
import { warn } from "@replayio/test-utils";
import { RecordingEntry } from "@replayio/test-utils";
import fs, { readFileSync, writeFileSync } from "fs";
Expand All @@ -14,15 +14,15 @@ function readXmlFile(path: string) {
}

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

return dom;
} catch (e) {
logger.error("ReadXmlFile:Failed", { path, error: e });
logError("ReadXmlFile:Failed", { path, error: e });
warn("[junit] Failed to read and parse reporter file", e);
}
}
Expand All @@ -43,7 +43,7 @@ function writeOutputFile(dom: (string | INode)[], outputFile: string) {
.join("\n");
writeFileSync(outputFile, updatedContents, "utf-8");
} catch (e) {
logger.error("WriteOutputFile:Failed", { outputFile, error: e });
logError("WriteOutputFile:Failed", { outputFile, error: e });
warn("[junit] Failed to update reporter file", e);
}
}
Expand Down Expand Up @@ -105,7 +105,7 @@ function addReplayLinkProperty(node: INode, replayUrls: string[]) {
)
);
} catch (e) {
logger.error("AddReplayLinkProperty:Failed", { error: e });
logError("AddReplayLinkProperty:Failed", { error: e });
}
}

Expand All @@ -116,13 +116,13 @@ function escapeForXml(content: string) {
function appendReplayUrlsToFailureNodes(node: INode, replayUrls: string[]) {
try {
const failures = findDescendentsByTagName(node, "failure");
logger.info("AppendReplayUrlsToFailures:Started", {
logInfo("AppendReplayUrlsToFailures:Started", {
failures: failures.length,
replayUrls,
});
failures.forEach(failure => {
if (typeof failure.children[0] !== "string") {
logger.info("AppendReplayUrlsToFailures:FailureNodeNotString", { failure });
logInfo("AppendReplayUrlsToFailures:FailureNodeNotString", { failure });
return;
}

Expand All @@ -133,7 +133,7 @@ function appendReplayUrlsToFailureNodes(node: INode, replayUrls: string[]) {
failure.children[0] = escapeForXml(output);
});
} catch (e) {
logger.error("AppendReplayUrlsToFailures:Failed", { error: e });
logError("AppendReplayUrlsToFailures:Failed", { error: e });
}
}

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

if (!rootSuite || !testSuites) {
logger.error("FindOutputFileForSpec:FailedToFindRootSuite", { dom });
logError("FindOutputFileForSpec:FailedToFindRootSuite", { dom });
continue;
}

Expand Down Expand Up @@ -181,15 +181,15 @@ export function updateJUnitReports(
mochaFile?: string
) {
try {
logger.info("UpdateJUnitReports:Started", {
logInfo("UpdateJUnitReports:Started", {
specRelativePath,
recordings: recordings.map(r => r.id),
projectBase,
mochaFile,
});

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

logger.info("UpdateJUnitReports:FoundRootSuite", { specRelativePath });
logInfo("UpdateJUnitReports:FoundRootSuite", { specRelativePath });

const testSuites = getTestSuitesNode(dom);
const rootSuite = getRootSuite(dom);
Expand All @@ -222,7 +222,7 @@ export function updateJUnitReports(

writeOutputFile(dom, xmlFile);
} catch (e) {
logger.error("UpdateJUnitReports:Failed", { specRelativePath, error: e });
logError("UpdateJUnitReports:Failed", { specRelativePath, error: e });
warn(`[junit] Unexpected reporter error for ${specRelativePath}`, e);
}
}
12 changes: 6 additions & 6 deletions packages/cypress/src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
type UploadOptions,
} from "@replayio/test-utils";

import { logger } from "@replay-cli/shared/logger";
import { logInfo } from "@replay-cli/shared/logger";
import { Errors } from "./error";
import { PluginFeature, getFeatures, isFeatureEnabled } from "./features";
import { appendToFixtureFile, initFixtureFile } from "./fixture";
Expand Down Expand Up @@ -76,7 +76,7 @@ class CypressReporter {
);

this.featureOptions = process.env.CYPRESS_REPLAY_PLUGIN_FEATURES;
logger.info("CypressReporter:InitializedWithFeatures", {
logInfo("CypressReporter:InitializedWithFeatures", {
features: getFeatures(this.featureOptions),
});
}
Expand All @@ -88,7 +88,7 @@ class CypressReporter {
async authenticate(apiKey: string) {
this.reporter.setApiKey(apiKey);
const { env } = await fetchWorkspaceConfig(apiKey);
logger.info("Authenticate:ExtraEnv", env);
logInfo("Authenticate:ExtraEnv", env);
this._extraEnv = env;
this.reporter.setDiagnosticMetadata(env);
}
Expand Down Expand Up @@ -116,13 +116,13 @@ class CypressReporter {
let currentCount = this.getStepCount();
const startTime = Date.now();
while (Date.now() < startTime + MAX_WAIT) {
logger.info("WaitingForStableStepCount:Count", { currentCount });
logInfo("WaitingForStableStepCount:Count", { currentCount });
const previousCount = currentCount;
await new Promise(resolve => setTimeout(resolve, 250));
currentCount = this.getStepCount();

if (previousCount === currentCount) {
logger.info("WaitingForStableStepCount:BreakCondition", {
logInfo("WaitingForStableStepCount:BreakCondition", {
currentCount,
duration: Date.now() - startTime,
});
Expand Down Expand Up @@ -200,7 +200,7 @@ class CypressReporter {
result.tests.length === 0
) {
const msg = "No test results found for spec " + spec.relative;
logger.info("GetTestResults:NoTestResults", { spec: spec.relative });
logInfo("GetTestResults:NoTestResults", { spec: spec.relative });
this.reporter.addError(new ReporterError(Errors.NoTestResults, msg, spec.relative));

return [
Expand Down
Loading