@empiricalrun/test-run 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @empiricalrun/test-run
2
2
 
3
+ ## 0.13.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [3ee1aec]
8
+ - @empiricalrun/r2-uploader@0.8.0
9
+
10
+ ## 0.13.0
11
+
12
+ ### Minor Changes
13
+
14
+ - d270c6d: feat: add cancellation watcher to self destruct
15
+ - 2d9919d: feat: consolidate zip utils and move to streaming
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [2d9919d]
20
+ - @empiricalrun/r2-uploader@0.7.0
21
+
3
22
  ## 0.12.0
4
23
 
5
24
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ import { Platform, TestCase } from "./types";
6
6
  import { getProjectsFromPlaywrightConfig } from "./utils/config";
7
7
  export { getProjectsFromPlaywrightConfig, parseTestListOutput, Platform, runSpecificTestsCmd, spawnCmd, };
8
8
  export * from "./glob-matcher";
9
+ export { type CancellationWatcher, startCancellationWatcher, } from "./lib/cancellation-watcher";
9
10
  export { filterArrayByGlobMatchersSet, generateProjectFilters } from "./utils";
10
11
  export declare function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, stdout, stderr, }: {
11
12
  testName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAI/E,OAAO,EAAkB,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EAAE,+BAA+B,EAAE,MAAM,gBAAgB,CAAC;AAMjE,OAAO,EACL,+BAA+B,EAC/B,mBAAmB,EACnB,QAAQ,EACR,mBAAmB,EACnB,QAAQ,GACT,CAAC;AACF,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAc/E,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC,GAAG,OAAO,CAAC;IACV,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,oBAAoB,CAAC;CACnC,CAAC,CAoBD;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACnE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjD,CAAC,CAeD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAI/E,OAAO,EAAkB,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EAAE,+BAA+B,EAAE,MAAM,gBAAgB,CAAC;AAMjE,OAAO,EACL,+BAA+B,EAC/B,mBAAmB,EACnB,QAAQ,EACR,mBAAmB,EACnB,QAAQ,GACT,CAAC;AACF,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,KAAK,mBAAmB,EACxB,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAc/E,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC,GAAG,OAAO,CAAC;IACV,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,oBAAoB,CAAC;CACnC,CAAC,CAoBD;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACnE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjD,CAAC,CAeD"}
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.spawnCmd = exports.runSpecificTestsCmd = exports.Platform = exports.parseTestListOutput = exports.getProjectsFromPlaywrightConfig = void 0;
20
+ exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.startCancellationWatcher = exports.spawnCmd = exports.runSpecificTestsCmd = exports.Platform = exports.parseTestListOutput = exports.getProjectsFromPlaywrightConfig = void 0;
21
21
  exports.runSingleTest = runSingleTest;
22
22
  exports.listProjectsAndTests = listProjectsAndTests;
23
23
  const fs_1 = __importDefault(require("fs"));
@@ -37,6 +37,8 @@ Object.defineProperty(exports, "getProjectsFromPlaywrightConfig", { enumerable:
37
37
  // The bin entrypoint has support for mobile also
38
38
  const supportedPlatform = types_1.Platform.WEB;
39
39
  __exportStar(require("./glob-matcher"), exports);
40
+ var cancellation_watcher_1 = require("./lib/cancellation-watcher");
41
+ Object.defineProperty(exports, "startCancellationWatcher", { enumerable: true, get: function () { return cancellation_watcher_1.startCancellationWatcher; } });
40
42
  var utils_2 = require("./utils");
41
43
  Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return utils_2.filterArrayByGlobMatchersSet; } });
42
44
  Object.defineProperty(exports, "generateProjectFilters", { enumerable: true, get: function () { return utils_2.generateProjectFilters; } });
@@ -0,0 +1,5 @@
1
+ export type CancellationWatcher = {
2
+ stop: () => void;
3
+ };
4
+ export declare function startCancellationWatcher(testRunId: string, apiKey: string, onCancel: () => void, pollIntervalMs?: number): CancellationWatcher;
5
+ //# sourceMappingURL=cancellation-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancellation-watcher.d.ts","sourceRoot":"","sources":["../../src/lib/cancellation-watcher.ts"],"names":[],"mappings":"AAqCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,IAAI,EACpB,cAAc,SAA2B,GACxC,mBAAmB,CAgCrB"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startCancellationWatcher = startCancellationWatcher;
4
+ const DOMAIN = process.env.DASHBOARD_DOMAIN || "https://dash.empirical.run";
5
+ const DEFAULT_POLL_INTERVAL_MS = 5000;
6
+ async function checkTestRunStatus(testRunId, apiKey) {
7
+ const url = `${DOMAIN}/api/test-runs/${testRunId}/status`;
8
+ try {
9
+ const response = await fetch(url, {
10
+ headers: { Authorization: `Bearer ${apiKey}` },
11
+ });
12
+ if (!response.ok) {
13
+ console.log(`[CancellationWatcher] Failed to check status: HTTP ${response.status} from ${url}`);
14
+ return { isTerminal: false, status: null };
15
+ }
16
+ const result = (await response.json());
17
+ const status = result.data || { isTerminal: false, status: null };
18
+ return status;
19
+ }
20
+ catch (error) {
21
+ const message = error instanceof Error ? error.message : String(error);
22
+ console.log(`[CancellationWatcher] Failed to check status: ${message}`);
23
+ return { isTerminal: false, status: null };
24
+ }
25
+ }
26
+ function startCancellationWatcher(testRunId, apiKey, onCancel, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS) {
27
+ let stopped = false;
28
+ console.log(`[CancellationWatcher] Starting watcher for test run ${testRunId} (polling every ${pollIntervalMs}ms)`);
29
+ console.log(`[CancellationWatcher] Dashboard domain: ${DOMAIN}`);
30
+ const poll = async () => {
31
+ while (!stopped) {
32
+ const { status } = await checkTestRunStatus(testRunId, apiKey);
33
+ if (status === "cancelling" || status === "cancelled") {
34
+ console.log(`[CancellationWatcher] Test run ${testRunId} is ${status}, triggering cancellation`);
35
+ onCancel();
36
+ stopped = true;
37
+ return;
38
+ }
39
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
40
+ }
41
+ };
42
+ poll();
43
+ return {
44
+ stop: () => {
45
+ console.log(`[CancellationWatcher] Stopping watcher for ${testRunId}`);
46
+ stopped = true;
47
+ },
48
+ };
49
+ }
package/dist/lib/cmd.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type ChildProcess } from "child_process";
1
2
  import { CommandToRun } from "../types";
2
3
  export declare function getCommandFromString(command: string): {
3
4
  command: string;
@@ -8,6 +9,7 @@ export declare function runTestsForCmd({ command, args, env }: CommandToRun, cwd
8
9
  stderr?: NodeJS.WritableStream;
9
10
  }): Promise<{
10
11
  hasTestPassed: boolean;
12
+ wasCancelled: boolean;
11
13
  }>;
12
14
  export declare function spawnCmd(command: string, args: string[], options: {
13
15
  cwd: string;
@@ -16,6 +18,7 @@ export declare function spawnCmd(command: string, args: string[], options: {
16
18
  throwOnError: boolean;
17
19
  stdout?: NodeJS.WritableStream;
18
20
  stderr?: NodeJS.WritableStream;
21
+ onSpawn?: (proc: ChildProcess) => void;
19
22
  }): Promise<{
20
23
  code: number;
21
24
  output?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/lib/cmd.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAeA;AAED,wBAAsB,cAAc,CAClC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,YAAY,EACpC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;;GAiBF;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IACP,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA+C5C"}
1
+ {"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/lib/cmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,eAAe,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMxC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAeA;AAED,wBAAsB,cAAc,CAClC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,YAAY,EACpC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;;;GAqEF;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IACP,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACxC,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiD5C"}
package/dist/lib/cmd.js CHANGED
@@ -5,6 +5,7 @@ exports.runTestsForCmd = runTestsForCmd;
5
5
  exports.spawnCmd = spawnCmd;
6
6
  const child_process_1 = require("child_process");
7
7
  const logger_1 = require("../logger");
8
+ const cancellation_watcher_1 = require("./cancellation-watcher");
8
9
  function getCommandFromString(command) {
9
10
  const regex = /[^\s"']+|"([^"]*)"|'([^']*)'/g;
10
11
  const matches = command.match(regex) || [];
@@ -21,7 +22,37 @@ function getCommandFromString(command) {
21
22
  }
22
23
  async function runTestsForCmd({ command, args, env }, cwd, options) {
23
24
  logger_1.logger.debug(`Running cmd: ${command} with args: ${args}`);
25
+ const testRunId = process.env.TEST_RUN_GITHUB_ACTION_ID;
26
+ const apiKey = process.env.EMPIRICALRUN_API_KEY;
27
+ console.log(`[CancellationWatcher] Environment: TEST_RUN_GITHUB_ACTION_ID=${testRunId}, EMPIRICALRUN_API_KEY=${apiKey ? "***" : "undefined"}`);
24
28
  let hasTestPassed = true;
29
+ let wasCancelled = false;
30
+ let cancellationWatcher;
31
+ let childProcess;
32
+ const cancelHandler = () => {
33
+ wasCancelled = true;
34
+ console.log(`[CancellationWatcher] Cancel handler invoked, killing child process (pid: ${childProcess?.pid})`);
35
+ if (childProcess && !childProcess.killed) {
36
+ // Use SIGTERM for more forceful termination that propagates to child processes
37
+ childProcess.kill("SIGTERM");
38
+ // Also try to kill the process group to ensure Playwright workers are stopped
39
+ if (childProcess.pid) {
40
+ try {
41
+ process.kill(-childProcess.pid, "SIGTERM");
42
+ console.log(`[CancellationWatcher] Sent SIGTERM to process group ${childProcess.pid}`);
43
+ }
44
+ catch {
45
+ // Process group kill may fail if not a group leader
46
+ }
47
+ }
48
+ }
49
+ };
50
+ if (testRunId && apiKey) {
51
+ cancellationWatcher = (0, cancellation_watcher_1.startCancellationWatcher)(testRunId, apiKey, cancelHandler);
52
+ }
53
+ else {
54
+ console.log("[CancellationWatcher] Not starting watcher - missing testRunId or apiKey");
55
+ }
25
56
  try {
26
57
  await spawnCmd(command, args, {
27
58
  cwd,
@@ -30,12 +61,18 @@ async function runTestsForCmd({ command, args, env }, cwd, options) {
30
61
  throwOnError: true,
31
62
  stdout: options?.stdout,
32
63
  stderr: options?.stderr,
64
+ onSpawn: (proc) => {
65
+ childProcess = proc;
66
+ },
33
67
  });
34
68
  }
35
69
  catch {
36
70
  hasTestPassed = false;
37
71
  }
38
- return { hasTestPassed };
72
+ finally {
73
+ cancellationWatcher?.stop();
74
+ }
75
+ return { hasTestPassed, wasCancelled };
39
76
  }
40
77
  async function spawnCmd(command, args, options) {
41
78
  let output = options.captureOutput ? "" : undefined;
@@ -44,9 +81,10 @@ async function spawnCmd(command, args, options) {
44
81
  const p = (0, child_process_1.spawn)(command, args, {
45
82
  env: { ...process.env, ...options.envOverrides },
46
83
  cwd: options.cwd,
47
- // Ensure child process receives signals
48
- detached: false,
84
+ // Create new process group so we can kill all child processes together
85
+ detached: true,
49
86
  });
87
+ options.onSpawn?.(p);
50
88
  // Setup signal handlers and get cleanup function
51
89
  const cleanupSignalHandlers = setupProcessSignalHandlers(p);
52
90
  p.stdout.on("data", (x) => {
@@ -0,0 +1,2 @@
1
+ export declare function patchMergedHtmlReport(htmlFilePath: string, urlMappings: Record<string, string>): Promise<void>;
2
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/html.ts"],"names":[],"mappings":"AAwEA,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CA8Gf"}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.patchMergedHtmlReport = patchMergedHtmlReport;
7
+ const zip_1 = require("@empiricalrun/r2-uploader/zip");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const logger_1 = require("../../logger");
11
+ const types_1 = require("./types");
12
+ function patchHtmlReportAttachments(report, urlMap) {
13
+ let patchCount = 0;
14
+ // report.json has files[].tests[], individual test files have tests[] directly
15
+ const tests = report.files
16
+ ? report.files.flatMap((f) => f.tests)
17
+ : report.tests || [];
18
+ for (const test of tests) {
19
+ for (const result of test.results || []) {
20
+ for (const attachment of result.attachments || []) {
21
+ if (attachment.path) {
22
+ for (const [fileName, url] of urlMap) {
23
+ if (attachment.path.endsWith(fileName)) {
24
+ attachment.path = url;
25
+ patchCount++;
26
+ break;
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ return patchCount;
34
+ }
35
+ async function patchMergedHtmlReport(htmlFilePath, urlMappings) {
36
+ if (Object.keys(urlMappings).length === 0) {
37
+ logger_1.logger.debug(`[Merge Reports] No URL mappings to apply`);
38
+ return;
39
+ }
40
+ let htmlContent;
41
+ const startTime = Date.now();
42
+ logger_1.logger.info(`[Merge Reports] Starting HTML patch...`);
43
+ try {
44
+ htmlContent = await fs_1.default.promises.readFile(htmlFilePath, "utf8");
45
+ logger_1.logger.info(`[Merge Reports] HTML file read: ${(htmlContent.length / 1024 / 1024).toFixed(2)} MB in ${Date.now() - startTime}ms`);
46
+ }
47
+ catch (error) {
48
+ logger_1.logger.error(`[Merge Reports] Failed to read HTML file:`, error);
49
+ return;
50
+ }
51
+ // Support both old format (1.53.x) and new format (1.57.0+)
52
+ const oldFormatMatch = htmlContent.match(/window\.playwrightReportBase64\s*=\s*"(?:data:application\/zip;base64,)?([^"]+)"/);
53
+ const newFormatMatch = htmlContent.match(/<script\s+id="playwrightReportBase64"[^>]*>(?:data:application\/zip;base64,)?([^<]+)<\/script>/);
54
+ const base64 = oldFormatMatch?.[1] || newFormatMatch?.[1];
55
+ if (!base64) {
56
+ logger_1.logger.error(`[Merge Reports] Base64 zip data not found in HTML`);
57
+ return;
58
+ }
59
+ const htmlDir = path_1.default.dirname(path_1.default.resolve(htmlFilePath));
60
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(htmlDir, "merge-patch-"));
61
+ const zipPath = path_1.default.join(tempDir, "archive.zip");
62
+ try {
63
+ let stepTime = Date.now();
64
+ await fs_1.default.promises.writeFile(zipPath, Buffer.from(base64, "base64"));
65
+ await (0, zip_1.extractZipToDirectory)(zipPath, tempDir);
66
+ await fs_1.default.promises.unlink(zipPath);
67
+ logger_1.logger.info(`[Merge Reports] Zip extracted in ${Date.now() - stepTime}ms`);
68
+ const jsonFiles = (await fs_1.default.promises.readdir(tempDir)).filter((f) => f.endsWith(".json"));
69
+ logger_1.logger.info(`[Merge Reports] Patching ${jsonFiles.length} JSON files with ${Object.keys(urlMappings).length} mappings`);
70
+ const urlMap = (0, types_1.buildUrlMap)(urlMappings);
71
+ stepTime = Date.now();
72
+ let totalPatchCount = 0;
73
+ const patchResults = await Promise.allSettled(jsonFiles.map(async (file) => {
74
+ const filePath = path_1.default.join(tempDir, file);
75
+ const content = await fs_1.default.promises.readFile(filePath, "utf8");
76
+ const report = JSON.parse(content);
77
+ const patchCount = patchHtmlReportAttachments(report, urlMap);
78
+ if (patchCount > 0) {
79
+ await fs_1.default.promises.writeFile(filePath, JSON.stringify(report), "utf8");
80
+ logger_1.logger.debug(`[Merge Reports] Patched ${file} (${patchCount} paths)`);
81
+ }
82
+ return patchCount;
83
+ }));
84
+ for (const result of patchResults) {
85
+ if (result.status === "rejected") {
86
+ logger_1.logger.error(`[Merge Reports] Failed to patch JSON file:`, result.reason);
87
+ }
88
+ else {
89
+ totalPatchCount += result.value;
90
+ }
91
+ }
92
+ logger_1.logger.info(`[Merge Reports] JSON patching completed in ${Date.now() - stepTime}ms (${totalPatchCount} paths patched)`);
93
+ stepTime = Date.now();
94
+ const newBuffer = await (0, zip_1.createZipFromDirectory)(tempDir);
95
+ const newBase64 = newBuffer.toString("base64");
96
+ logger_1.logger.info(`[Merge Reports] New zip created in ${Date.now() - stepTime}ms`);
97
+ let updatedHtml;
98
+ if (oldFormatMatch) {
99
+ updatedHtml = htmlContent.replace(/(window\.playwrightReportBase64\s*=\s*")(?:data:application\/zip;base64,)?[^"]*(")/, `$1data:application/zip;base64,${newBase64}$2`);
100
+ }
101
+ else {
102
+ updatedHtml = htmlContent.replace(/(<script\s+id="playwrightReportBase64"[^>]*>)(?:data:application\/zip;base64,)?[^<]*(<\/script>)/, `$1data:application/zip;base64,${newBase64}$2`);
103
+ }
104
+ await fs_1.default.promises.writeFile(htmlFilePath, updatedHtml, "utf8");
105
+ logger_1.logger.info(`[Merge Reports] HTML file patched successfully`);
106
+ }
107
+ catch (error) {
108
+ logger_1.logger.error(`[Merge Reports] Failed to patch HTML:`, error);
109
+ }
110
+ finally {
111
+ await fs_1.default.promises.rm(tempDir, { recursive: true, force: true });
112
+ }
113
+ }
@@ -0,0 +1,16 @@
1
+ import type { MergeReportsOptions, UploadOptions } from "./types";
2
+ export { patchMergedHtmlReport } from "./html";
3
+ export { patchSummaryJson } from "./json";
4
+ export type { MergeReportsOptions, UploadOptions } from "./types";
5
+ export declare function runPlaywrightMergeReports(options: MergeReportsOptions): Promise<{
6
+ success: boolean;
7
+ }>;
8
+ export declare function extractUrlMappingsFromBlobs(blobDir: string): Promise<Record<string, string>>;
9
+ export declare function uploadMergedReports(cwd: string, outputDir: string, uploadOptions: UploadOptions): Promise<void>;
10
+ export declare function mergeReports(options: {
11
+ blobDir?: string;
12
+ cwd?: string;
13
+ }): Promise<{
14
+ success: boolean;
15
+ }>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA2B/B;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoCjC;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAyDhC"}
@@ -3,18 +3,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.patchSummaryJson = exports.patchMergedHtmlReport = void 0;
6
7
  exports.runPlaywrightMergeReports = runPlaywrightMergeReports;
7
8
  exports.extractUrlMappingsFromBlobs = extractUrlMappingsFromBlobs;
8
- exports.patchMergedHtmlReport = patchMergedHtmlReport;
9
- exports.patchSummaryJson = patchSummaryJson;
10
9
  exports.uploadMergedReports = uploadMergedReports;
11
10
  exports.mergeReports = mergeReports;
12
11
  const r2_uploader_1 = require("@empiricalrun/r2-uploader");
13
- const adm_zip_1 = __importDefault(require("adm-zip"));
12
+ const zip_1 = require("@empiricalrun/r2-uploader/zip");
14
13
  const fs_1 = __importDefault(require("fs"));
15
14
  const path_1 = __importDefault(require("path"));
16
- const logger_1 = require("../logger");
17
- const cmd_1 = require("./cmd");
15
+ const logger_1 = require("../../logger");
16
+ const cmd_1 = require("../cmd");
17
+ const html_1 = require("./html");
18
+ const json_1 = require("./json");
19
+ var html_2 = require("./html");
20
+ Object.defineProperty(exports, "patchMergedHtmlReport", { enumerable: true, get: function () { return html_2.patchMergedHtmlReport; } });
21
+ var json_2 = require("./json");
22
+ Object.defineProperty(exports, "patchSummaryJson", { enumerable: true, get: function () { return json_2.patchSummaryJson; } });
18
23
  async function runPlaywrightMergeReports(options) {
19
24
  const { blobDir, outputDir, cwd } = options;
20
25
  logger_1.logger.debug(`[Merge Reports] Running playwright merge-reports`);
@@ -38,109 +43,31 @@ async function runPlaywrightMergeReports(options) {
38
43
  return { success: false };
39
44
  }
40
45
  }
41
- function extractUrlMappingsFromBlobs(blobDir) {
46
+ async function extractUrlMappingsFromBlobs(blobDir) {
42
47
  const combinedMap = {};
43
48
  const files = fs_1.default.readdirSync(blobDir);
44
- for (const fileName of files.filter((f) => f.endsWith(".zip"))) {
49
+ const zipFiles = files.filter((f) => f.endsWith(".zip"));
50
+ const results = await Promise.allSettled(zipFiles.map(async (fileName) => {
45
51
  const zipPath = path_1.default.join(blobDir, fileName);
46
- try {
47
- const zip = new adm_zip_1.default(zipPath);
48
- const urlsEntry = zip.getEntry("_empirical_urls.json");
49
- if (urlsEntry) {
50
- const content = JSON.parse(urlsEntry.getData().toString("utf8"));
51
- Object.assign(combinedMap, content);
52
- logger_1.logger.debug(`[Merge Reports] Extracted ${Object.keys(content).length} URL mappings from ${fileName}`);
53
- }
52
+ const buffer = await (0, zip_1.readZipEntry)(zipPath, "_empirical_urls.json");
53
+ if (buffer) {
54
+ const content = JSON.parse(buffer.toString("utf8"));
55
+ logger_1.logger.debug(`[Merge Reports] Extracted ${Object.keys(content).length} URL mappings from ${fileName}`);
56
+ return content;
54
57
  }
55
- catch (error) {
56
- logger_1.logger.error(`[Merge Reports] Failed to extract URL mappings from ${fileName}:`, error);
58
+ return null;
59
+ }));
60
+ for (const result of results) {
61
+ if (result.status === "fulfilled" && result.value) {
62
+ Object.assign(combinedMap, result.value);
63
+ }
64
+ else if (result.status === "rejected") {
65
+ logger_1.logger.error(`[Merge Reports] Failed to extract URL mappings:`, result.reason);
57
66
  }
58
67
  }
59
68
  logger_1.logger.info(`[Merge Reports] Total URL mappings: ${Object.keys(combinedMap).length}`);
60
69
  return combinedMap;
61
70
  }
62
- async function patchMergedHtmlReport(htmlFilePath, urlMappings) {
63
- if (Object.keys(urlMappings).length === 0) {
64
- logger_1.logger.debug(`[Merge Reports] No URL mappings to apply`);
65
- return;
66
- }
67
- let htmlContent;
68
- try {
69
- htmlContent = await fs_1.default.promises.readFile(htmlFilePath, "utf8");
70
- }
71
- catch (error) {
72
- logger_1.logger.error(`[Merge Reports] Failed to read HTML file:`, error);
73
- return;
74
- }
75
- const oldFormatMatch = htmlContent.match(/window\.playwrightReportBase64\s*=\s*"(?:data:application\/zip;base64,)?([^"]+)"/);
76
- const newFormatMatch = htmlContent.match(/<script\s+id="playwrightReportBase64"[^>]*>(?:data:application\/zip;base64,)?([^<]+)<\/script>/);
77
- const base64 = oldFormatMatch?.[1] || newFormatMatch?.[1];
78
- if (!base64) {
79
- logger_1.logger.error(`[Merge Reports] Base64 zip data not found in HTML`);
80
- return;
81
- }
82
- const htmlDir = path_1.default.dirname(path_1.default.resolve(htmlFilePath));
83
- const tempDir = fs_1.default.mkdtempSync(path_1.default.join(htmlDir, "merge-patch-"));
84
- const zipPath = path_1.default.join(tempDir, "archive.zip");
85
- try {
86
- await fs_1.default.promises.writeFile(zipPath, Buffer.from(base64, "base64"));
87
- const zip = new adm_zip_1.default(zipPath);
88
- zip.extractAllTo(tempDir, true);
89
- await fs_1.default.promises.unlink(zipPath);
90
- const jsonFiles = (await fs_1.default.promises.readdir(tempDir)).filter((f) => f.endsWith(".json"));
91
- for (const file of jsonFiles) {
92
- const filePath = path_1.default.join(tempDir, file);
93
- const content = await fs_1.default.promises.readFile(filePath, "utf8");
94
- let modified = content;
95
- for (const [resourcePath, url] of Object.entries(urlMappings)) {
96
- const resourceFileName = resourcePath.replace(/^resources\//, "");
97
- const regex = new RegExp(`[^"]*${resourceFileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "g");
98
- modified = modified.replace(regex, url);
99
- }
100
- if (modified !== content) {
101
- await fs_1.default.promises.writeFile(filePath, modified, "utf8");
102
- logger_1.logger.debug(`[Merge Reports] Patched ${file}`);
103
- }
104
- }
105
- const newZip = new adm_zip_1.default();
106
- newZip.addLocalFolder(tempDir);
107
- const newBase64 = newZip.toBuffer().toString("base64");
108
- let updatedHtml;
109
- if (oldFormatMatch) {
110
- updatedHtml = htmlContent.replace(/(window\.playwrightReportBase64\s*=\s*")(?:data:application\/zip;base64,)?[^"]*(")/, `$1data:application/zip;base64,${newBase64}$2`);
111
- }
112
- else {
113
- updatedHtml = htmlContent.replace(/(<script\s+id="playwrightReportBase64"[^>]*>)(?:data:application\/zip;base64,)?[^<]*(<\/script>)/, `$1data:application/zip;base64,${newBase64}$2`);
114
- }
115
- await fs_1.default.promises.writeFile(htmlFilePath, updatedHtml, "utf8");
116
- logger_1.logger.info(`[Merge Reports] HTML file patched successfully`);
117
- }
118
- catch (error) {
119
- logger_1.logger.error(`[Merge Reports] Failed to patch HTML:`, error);
120
- }
121
- finally {
122
- await fs_1.default.promises.rm(tempDir, { recursive: true, force: true });
123
- }
124
- }
125
- async function patchSummaryJson(jsonFilePath, urlMappings) {
126
- if (Object.keys(urlMappings).length === 0) {
127
- logger_1.logger.debug(`[Merge Reports] No URL mappings to apply to summary.json`);
128
- return;
129
- }
130
- try {
131
- let content = await fs_1.default.promises.readFile(jsonFilePath, "utf8");
132
- for (const [resourcePath, url] of Object.entries(urlMappings)) {
133
- const resourceFileName = resourcePath.replace(/^resources\//, "");
134
- const regex = new RegExp(`[^"]*${resourceFileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "g");
135
- content = content.replace(regex, url);
136
- }
137
- await fs_1.default.promises.writeFile(jsonFilePath, content, "utf8");
138
- logger_1.logger.info(`[Merge Reports] summary.json patched successfully`);
139
- }
140
- catch (error) {
141
- logger_1.logger.error(`[Merge Reports] Failed to patch summary.json:`, error);
142
- }
143
- }
144
71
  async function uploadMergedReports(cwd, outputDir, uploadOptions) {
145
72
  const { projectName, runId, baseUrl, uploadBucket } = uploadOptions;
146
73
  const destinationDir = path_1.default.join(projectName, runId);
@@ -200,7 +127,7 @@ async function mergeReports(options) {
200
127
  logger_1.logger.error(`[Merge Reports] Blob directory does not exist: ${blobDir}`);
201
128
  return { success: false };
202
129
  }
203
- const urlMappings = extractUrlMappingsFromBlobs(blobDir);
130
+ const urlMappings = await extractUrlMappingsFromBlobs(blobDir);
204
131
  const { success } = await runPlaywrightMergeReports({
205
132
  blobDir,
206
133
  outputDir,
@@ -211,8 +138,10 @@ async function mergeReports(options) {
211
138
  }
212
139
  const htmlFilePath = path_1.default.join(outputDir, "index.html");
213
140
  const jsonFilePath = path_1.default.join(cwd, "summary.json");
214
- await patchMergedHtmlReport(htmlFilePath, urlMappings);
215
- await patchSummaryJson(jsonFilePath, urlMappings);
141
+ await Promise.all([
142
+ (0, html_1.patchMergedHtmlReport)(htmlFilePath, urlMappings),
143
+ (0, json_1.patchSummaryJson)(jsonFilePath, urlMappings),
144
+ ]);
216
145
  const hasR2Creds = process.env.R2_ACCOUNT_ID &&
217
146
  process.env.R2_ACCESS_KEY_ID &&
218
147
  process.env.R2_SECRET_ACCESS_KEY;
@@ -0,0 +1,2 @@
1
+ export declare function patchSummaryJson(jsonFilePath: string, urlMappings: Record<string, string>): Promise<void>;
2
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/json.ts"],"names":[],"mappings":"AA8EA,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAyCf"}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.patchSummaryJson = patchSummaryJson;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const logger_1 = require("../../logger");
9
+ const types_1 = require("./types");
10
+ function patchAttachmentPaths(report, urlMap) {
11
+ let patchCount = 0;
12
+ function processSuite(suite) {
13
+ for (const spec of suite.specs) {
14
+ for (const test of spec.tests) {
15
+ for (const result of test.results) {
16
+ for (const attachment of result.attachments) {
17
+ if (attachment.path) {
18
+ for (const [fileName, url] of urlMap) {
19
+ if (attachment.path.endsWith(fileName)) {
20
+ attachment.path = url;
21
+ patchCount++;
22
+ break;
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ if (suite.suites) {
31
+ for (const nested of suite.suites) {
32
+ processSuite(nested);
33
+ }
34
+ }
35
+ }
36
+ for (const suite of report.suites) {
37
+ processSuite(suite);
38
+ }
39
+ return patchCount;
40
+ }
41
+ async function patchSummaryJson(jsonFilePath, urlMappings) {
42
+ if (Object.keys(urlMappings).length === 0) {
43
+ logger_1.logger.debug(`[Merge Reports] No URL mappings to apply to summary.json`);
44
+ return;
45
+ }
46
+ const startTime = Date.now();
47
+ logger_1.logger.info(`[Merge Reports] Starting summary.json patch...`);
48
+ try {
49
+ let stepTime = Date.now();
50
+ const content = await fs_1.default.promises.readFile(jsonFilePath, "utf8");
51
+ logger_1.logger.info(`[Merge Reports] summary.json read: ${(content.length / 1024).toFixed(2)} KB in ${Date.now() - stepTime}ms`);
52
+ stepTime = Date.now();
53
+ const report = JSON.parse(content);
54
+ logger_1.logger.info(`[Merge Reports] summary.json parsed in ${Date.now() - stepTime}ms`);
55
+ stepTime = Date.now();
56
+ const urlMap = (0, types_1.buildUrlMap)(urlMappings);
57
+ const patchCount = patchAttachmentPaths(report, urlMap);
58
+ logger_1.logger.info(`[Merge Reports] summary.json patched ${patchCount} attachment paths in ${Date.now() - stepTime}ms`);
59
+ stepTime = Date.now();
60
+ await fs_1.default.promises.writeFile(jsonFilePath, JSON.stringify(report), "utf8");
61
+ logger_1.logger.info(`[Merge Reports] summary.json written in ${Date.now() - stepTime}ms`);
62
+ logger_1.logger.info(`[Merge Reports] summary.json patched successfully (total: ${Date.now() - startTime}ms)`);
63
+ }
64
+ catch (error) {
65
+ logger_1.logger.error(`[Merge Reports] Failed to patch summary.json:`, error);
66
+ }
67
+ }
@@ -0,0 +1,13 @@
1
+ export interface MergeReportsOptions {
2
+ blobDir: string;
3
+ outputDir: string;
4
+ cwd: string;
5
+ }
6
+ export interface UploadOptions {
7
+ projectName: string;
8
+ runId: string;
9
+ baseUrl: string;
10
+ uploadBucket: string;
11
+ }
12
+ export declare function buildUrlMap(urlMappings: Record<string, string>): Map<string, string>;
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOrB"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildUrlMap = buildUrlMap;
4
+ function buildUrlMap(urlMappings) {
5
+ const map = new Map();
6
+ for (const [resourcePath, url] of Object.entries(urlMappings)) {
7
+ const fileName = resourcePath.replace(/^resources\//, "");
8
+ map.set(fileName, url);
9
+ }
10
+ return map;
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-run",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -26,18 +26,16 @@
26
26
  },
27
27
  "author": "Empirical Team <hey@empirical.run>",
28
28
  "dependencies": {
29
- "adm-zip": "^0.5.16",
30
29
  "async-retry": "^1.3.3",
31
30
  "commander": "^12.1.0",
32
31
  "console-log-level": "^1.4.1",
33
32
  "dotenv": "^16.4.5",
34
33
  "minimatch": "^10.0.1",
35
34
  "ts-morph": "^23.0.0",
36
- "@empiricalrun/r2-uploader": "^0.6.0"
35
+ "@empiricalrun/r2-uploader": "^0.8.0"
37
36
  },
38
37
  "devDependencies": {
39
38
  "@playwright/test": "1.53.2",
40
- "@types/adm-zip": "^0.5.7",
41
39
  "@types/async-retry": "^1.4.8",
42
40
  "@types/console-log-level": "^1.4.5",
43
41
  "@types/node": "^22.5.5",
@@ -1 +1 @@
1
- {"root":["./src/dashboard.ts","./src/glob-matcher.ts","./src/index.ts","./src/logger.ts","./src/bin/index.ts","./src/bin/merge-reports.ts","./src/lib/cmd.ts","./src/lib/merge-reports.ts","./src/lib/run-all-tests.ts","./src/lib/run-specific-test.ts","./src/lib/memfs/read-hello-world.ts","./src/stdout-parser/index.ts","./src/types/index.ts","./src/utils/config-parser.ts","./src/utils/config.ts","./src/utils/index.ts"],"version":"5.8.3"}
1
+ {"root":["./src/dashboard.ts","./src/glob-matcher.ts","./src/index.ts","./src/logger.ts","./src/bin/index.ts","./src/bin/merge-reports.ts","./src/lib/cancellation-watcher.ts","./src/lib/cmd.ts","./src/lib/run-all-tests.ts","./src/lib/run-specific-test.ts","./src/lib/memfs/read-hello-world.ts","./src/lib/merge-reports/html.ts","./src/lib/merge-reports/index.ts","./src/lib/merge-reports/json.ts","./src/lib/merge-reports/types.ts","./src/stdout-parser/index.ts","./src/types/index.ts","./src/utils/config-parser.ts","./src/utils/config.ts","./src/utils/index.ts"],"version":"5.8.3"}
@@ -1,26 +0,0 @@
1
- interface MergeReportsOptions {
2
- blobDir: string;
3
- outputDir: string;
4
- cwd: string;
5
- }
6
- interface UploadOptions {
7
- projectName: string;
8
- runId: string;
9
- baseUrl: string;
10
- uploadBucket: string;
11
- }
12
- export declare function runPlaywrightMergeReports(options: MergeReportsOptions): Promise<{
13
- success: boolean;
14
- }>;
15
- export declare function extractUrlMappingsFromBlobs(blobDir: string): Record<string, string>;
16
- export declare function patchMergedHtmlReport(htmlFilePath: string, urlMappings: Record<string, string>): Promise<void>;
17
- export declare function patchSummaryJson(jsonFilePath: string, urlMappings: Record<string, string>): Promise<void>;
18
- export declare function uploadMergedReports(cwd: string, outputDir: string, uploadOptions: UploadOptions): Promise<void>;
19
- export declare function mergeReports(options: {
20
- blobDir?: string;
21
- cwd?: string;
22
- }): Promise<{
23
- success: boolean;
24
- }>;
25
- export {};
26
- //# sourceMappingURL=merge-reports.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"merge-reports.d.ts","sourceRoot":"","sources":["../../src/lib/merge-reports.ts"],"names":[],"mappings":"AAYA,UAAU,mBAAmB;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA2B/B;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BxB;AAED,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAqFf;AAED,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAuDhC"}