@empiricalrun/test-run 0.11.0 → 0.12.0

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,22 @@
1
1
  # @empiricalrun/test-run
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 79a4e0f: feat: add blob reporters for sharding
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [79a4e0f]
12
+ - @empiricalrun/r2-uploader@0.6.0
13
+
14
+ ## 0.11.1
15
+
16
+ ### Patch Changes
17
+
18
+ - 9fb0ba1: feat: reuse glob matcher for envs to show on dash
19
+
3
20
  ## 0.11.0
4
21
 
5
22
  ### Minor Changes
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=merge-reports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-reports.d.ts","sourceRoot":"","sources":["../../src/bin/merge-reports.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const dotenv_1 = __importDefault(require("dotenv"));
9
+ const merge_reports_1 = require("../lib/merge-reports");
10
+ dotenv_1.default.config({
11
+ path: [".env.local", ".env"],
12
+ });
13
+ (async function main() {
14
+ commander_1.program
15
+ .option("-b, --blob-dir <blob-dir>", "Path to the blob-report directory")
16
+ .option("-c, --cwd <cwd>", "Working directory")
17
+ .parse(process.argv);
18
+ const options = commander_1.program.opts();
19
+ const { success } = await (0, merge_reports_1.mergeReports)({
20
+ blobDir: options.blobDir,
21
+ cwd: options.cwd,
22
+ });
23
+ if (!success) {
24
+ process.exit(1);
25
+ }
26
+ })();
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Filters an array using glob pattern matchers.
3
+ *
4
+ * @param input - Array that needs to be filtered
5
+ * @param globMatcherSets - Set of glob patterns to filter the array sequentially (takes the intersection of all sets)
6
+ * @returns Filtered array containing only items that match all glob pattern sets
7
+ */
8
+ export declare const filterArrayByGlobMatchersSet: (input: string[], globMatcherSets: string[][]) => string[];
9
+ /**
10
+ * Filters playwright project names using glob patterns.
11
+ *
12
+ * @param allProjectNames - Array of all available project names
13
+ * @param patterns - Array of glob patterns to match against
14
+ * @returns Array of project names that match the patterns
15
+ */
16
+ export declare const filterProjectsByGlobPatterns: (allProjectNames: string[], patterns: string[]) => string[];
17
+ //# sourceMappingURL=glob-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob-matcher.d.ts","sourceRoot":"","sources":["../src/glob-matcher.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACvC,OAAO,MAAM,EAAE,EACf,iBAAiB,MAAM,EAAE,EAAE,KAC1B,MAAM,EAUR,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACvC,iBAAiB,MAAM,EAAE,EACzB,UAAU,MAAM,EAAE,KACjB,MAAM,EASR,CAAC"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterProjectsByGlobPatterns = exports.filterArrayByGlobMatchersSet = void 0;
4
+ const minimatch_1 = require("minimatch");
5
+ /**
6
+ * Filters an array using glob pattern matchers.
7
+ *
8
+ * @param input - Array that needs to be filtered
9
+ * @param globMatcherSets - Set of glob patterns to filter the array sequentially (takes the intersection of all sets)
10
+ * @returns Filtered array containing only items that match all glob pattern sets
11
+ */
12
+ const filterArrayByGlobMatchersSet = (input, globMatcherSets) => {
13
+ let filteredList = input;
14
+ globMatcherSets.forEach((matcherSet) => {
15
+ filteredList = filteredList.filter((item) => {
16
+ return matcherSet.some((matcherGlob) => (0, minimatch_1.minimatch)(item, matcherGlob));
17
+ });
18
+ });
19
+ return filteredList;
20
+ };
21
+ exports.filterArrayByGlobMatchersSet = filterArrayByGlobMatchersSet;
22
+ /**
23
+ * Filters playwright project names using glob patterns.
24
+ *
25
+ * @param allProjectNames - Array of all available project names
26
+ * @param patterns - Array of glob patterns to match against
27
+ * @returns Array of project names that match the patterns
28
+ */
29
+ const filterProjectsByGlobPatterns = (allProjectNames, patterns) => {
30
+ if (!patterns || patterns.length === 0) {
31
+ return [];
32
+ }
33
+ // Convert patterns to the format expected by filterArrayByGlobMatchersSet
34
+ const globMatcherSets = patterns.map((pattern) => [pattern]);
35
+ return (0, exports.filterArrayByGlobMatchersSet)(allProjectNames, globMatcherSets);
36
+ };
37
+ exports.filterProjectsByGlobPatterns = filterProjectsByGlobPatterns;
package/dist/index.d.ts CHANGED
@@ -1,17 +1,21 @@
1
1
  import { JSONReport as PlaywrightJSONReport } from "@playwright/test/reporter";
2
2
  import { spawnCmd } from "./lib/cmd";
3
3
  import { runSpecificTestsCmd } from "./lib/run-specific-test";
4
+ import { parseTestListOutput } from "./stdout-parser";
4
5
  import { Platform, TestCase } from "./types";
5
6
  import { getProjectsFromPlaywrightConfig } from "./utils/config";
6
- export { getProjectsFromPlaywrightConfig, Platform, runSpecificTestsCmd, spawnCmd, };
7
+ export { getProjectsFromPlaywrightConfig, parseTestListOutput, Platform, runSpecificTestsCmd, spawnCmd, };
8
+ export * from "./glob-matcher";
7
9
  export { filterArrayByGlobMatchersSet, generateProjectFilters } from "./utils";
8
- export declare function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, }: {
10
+ export declare function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, stdout, stderr, }: {
9
11
  testName: string;
10
12
  suites: string[];
11
13
  filePath: string;
12
14
  projects: string[];
13
15
  envOverrides?: Record<string, string>;
14
16
  repoDir: string;
17
+ stdout?: NodeJS.WritableStream;
18
+ stderr?: NodeJS.WritableStream;
15
19
  }): Promise<{
16
20
  hasTestPassed: boolean;
17
21
  summaryJson: PlaywrightJSONReport;
@@ -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;AAE9D,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,QAAQ,EACR,mBAAmB,EACnB,QAAQ,GACT,CAAC;AACF,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,GACR,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;CACjB,GAAG,OAAO,CAAC;IACV,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,oBAAoB,CAAC;CACnC,CAAC,CAiBD;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,CAaD"}
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"}
package/dist/index.js CHANGED
@@ -1,9 +1,23 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
18
  };
5
19
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.spawnCmd = exports.runSpecificTestsCmd = exports.Platform = exports.getProjectsFromPlaywrightConfig = void 0;
20
+ exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.spawnCmd = exports.runSpecificTestsCmd = exports.Platform = exports.parseTestListOutput = exports.getProjectsFromPlaywrightConfig = void 0;
7
21
  exports.runSingleTest = runSingleTest;
8
22
  exports.listProjectsAndTests = listProjectsAndTests;
9
23
  const fs_1 = __importDefault(require("fs"));
@@ -12,7 +26,8 @@ const cmd_1 = require("./lib/cmd");
12
26
  Object.defineProperty(exports, "spawnCmd", { enumerable: true, get: function () { return cmd_1.spawnCmd; } });
13
27
  const run_specific_test_1 = require("./lib/run-specific-test");
14
28
  Object.defineProperty(exports, "runSpecificTestsCmd", { enumerable: true, get: function () { return run_specific_test_1.runSpecificTestsCmd; } });
15
- const parser_1 = require("./parser");
29
+ const stdout_parser_1 = require("./stdout-parser");
30
+ Object.defineProperty(exports, "parseTestListOutput", { enumerable: true, get: function () { return stdout_parser_1.parseTestListOutput; } });
16
31
  const types_1 = require("./types");
17
32
  Object.defineProperty(exports, "Platform", { enumerable: true, get: function () { return types_1.Platform; } });
18
33
  const utils_1 = require("./utils");
@@ -21,6 +36,7 @@ Object.defineProperty(exports, "getProjectsFromPlaywrightConfig", { enumerable:
21
36
  // For test-run package, the library entrypoint, we only support web platform
22
37
  // The bin entrypoint has support for mobile also
23
38
  const supportedPlatform = types_1.Platform.WEB;
39
+ __exportStar(require("./glob-matcher"), exports);
24
40
  var utils_2 = require("./utils");
25
41
  Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return utils_2.filterArrayByGlobMatchersSet; } });
26
42
  Object.defineProperty(exports, "generateProjectFilters", { enumerable: true, get: function () { return utils_2.generateProjectFilters; } });
@@ -31,7 +47,7 @@ function getSummaryJsonPath(repoDir) {
31
47
  ? pathForPlaywright147
32
48
  : pathForOtherPlaywrightVersions;
33
49
  }
34
- async function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, }) {
50
+ async function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, stdout, stderr, }) {
35
51
  const testDir = "tests";
36
52
  const commandToRun = await (0, run_specific_test_1.runSpecificTestsCmd)({
37
53
  tests: [{ name: testName, dir: testDir, filePath, suites }],
@@ -40,7 +56,10 @@ async function runSingleTest({ testName, suites, filePath, projects, envOverride
40
56
  platform: supportedPlatform,
41
57
  repoDir,
42
58
  });
43
- const { hasTestPassed } = await (0, cmd_1.runTestsForCmd)(commandToRun, repoDir);
59
+ const { hasTestPassed } = await (0, cmd_1.runTestsForCmd)(commandToRun, repoDir, {
60
+ stdout,
61
+ stderr,
62
+ });
44
63
  const jsonFilePath = getSummaryJsonPath(repoDir);
45
64
  const jsonFileContents = fs_1.default.readFileSync(jsonFilePath, "utf8");
46
65
  const summaryJson = JSON.parse(jsonFileContents);
@@ -54,12 +73,14 @@ async function listProjectsAndTests(repoDir) {
54
73
  const args = [testRunner, "test", "--list"];
55
74
  const { output, code } = await (0, cmd_1.spawnCmd)("npx", args, {
56
75
  cwd: repoDir,
57
- envOverrides: {},
76
+ envOverrides: {
77
+ NODE_PATH: path_1.default.join(repoDir, "node_modules"),
78
+ },
58
79
  captureOutput: true,
59
80
  throwOnError: true,
60
81
  });
61
82
  if (!output) {
62
83
  throw new Error(`Failed to run list command; exit code: ${code}`);
63
84
  }
64
- return (0, parser_1.parseTestListOutput)(output);
85
+ return (0, stdout_parser_1.parseTestListOutput)(output);
65
86
  }
package/dist/lib/cmd.d.ts CHANGED
@@ -3,7 +3,10 @@ export declare function getCommandFromString(command: string): {
3
3
  command: string;
4
4
  args: string[];
5
5
  };
6
- export declare function runTestsForCmd({ command, args, env }: CommandToRun, cwd: string): Promise<{
6
+ export declare function runTestsForCmd({ command, args, env }: CommandToRun, cwd: string, options?: {
7
+ stdout?: NodeJS.WritableStream;
8
+ stderr?: NodeJS.WritableStream;
9
+ }): Promise<{
7
10
  hasTestPassed: boolean;
8
11
  }>;
9
12
  export declare function spawnCmd(command: string, args: string[], options: {
@@ -11,6 +14,8 @@ export declare function spawnCmd(command: string, args: string[], options: {
11
14
  envOverrides: Record<string, string>;
12
15
  captureOutput: boolean;
13
16
  throwOnError: boolean;
17
+ stdout?: NodeJS.WritableStream;
18
+ stderr?: NodeJS.WritableStream;
14
19
  }): Promise<{
15
20
  code: number;
16
21
  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;;GAeZ;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;CACvB,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6C5C"}
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"}
package/dist/lib/cmd.js CHANGED
@@ -19,7 +19,7 @@ function getCommandFromString(command) {
19
19
  }),
20
20
  };
21
21
  }
22
- async function runTestsForCmd({ command, args, env }, cwd) {
22
+ async function runTestsForCmd({ command, args, env }, cwd, options) {
23
23
  logger_1.logger.debug(`Running cmd: ${command} with args: ${args}`);
24
24
  let hasTestPassed = true;
25
25
  try {
@@ -28,6 +28,8 @@ async function runTestsForCmd({ command, args, env }, cwd) {
28
28
  envOverrides: env,
29
29
  captureOutput: false,
30
30
  throwOnError: true,
31
+ stdout: options?.stdout,
32
+ stderr: options?.stderr,
31
33
  });
32
34
  }
33
35
  catch {
@@ -53,7 +55,8 @@ async function spawnCmd(command, args, options) {
53
55
  output += log;
54
56
  }
55
57
  else {
56
- process.stdout.write(log);
58
+ const stdout = options.stdout || process.stdout;
59
+ stdout.write(log);
57
60
  }
58
61
  if (log.includes("Error")) {
59
62
  errorLogs.push(log);
@@ -61,7 +64,8 @@ async function spawnCmd(command, args, options) {
61
64
  });
62
65
  p.stderr.on("data", (x) => {
63
66
  const log = x.toString();
64
- process.stderr.write(log);
67
+ const stderr = options.stderr || process.stderr;
68
+ stderr.write(log);
65
69
  errorLogs.push(log);
66
70
  });
67
71
  p.on("exit", (code) => {
@@ -0,0 +1,26 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,231 @@
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.runPlaywrightMergeReports = runPlaywrightMergeReports;
7
+ exports.extractUrlMappingsFromBlobs = extractUrlMappingsFromBlobs;
8
+ exports.patchMergedHtmlReport = patchMergedHtmlReport;
9
+ exports.patchSummaryJson = patchSummaryJson;
10
+ exports.uploadMergedReports = uploadMergedReports;
11
+ exports.mergeReports = mergeReports;
12
+ const r2_uploader_1 = require("@empiricalrun/r2-uploader");
13
+ const adm_zip_1 = __importDefault(require("adm-zip"));
14
+ const fs_1 = __importDefault(require("fs"));
15
+ const path_1 = __importDefault(require("path"));
16
+ const logger_1 = require("../logger");
17
+ const cmd_1 = require("./cmd");
18
+ async function runPlaywrightMergeReports(options) {
19
+ const { blobDir, outputDir, cwd } = options;
20
+ logger_1.logger.debug(`[Merge Reports] Running playwright merge-reports`);
21
+ logger_1.logger.debug(`[Merge Reports] Blob dir: ${blobDir}`);
22
+ logger_1.logger.debug(`[Merge Reports] Output dir: ${outputDir}`);
23
+ try {
24
+ await (0, cmd_1.spawnCmd)("npx", ["playwright", "merge-reports", blobDir, "--reporter", "html,json"], {
25
+ cwd,
26
+ envOverrides: {
27
+ PLAYWRIGHT_HTML_OPEN: "never",
28
+ PLAYWRIGHT_HTML_OUTPUT_DIR: outputDir,
29
+ PLAYWRIGHT_JSON_OUTPUT_NAME: path_1.default.join(cwd, "summary.json"),
30
+ },
31
+ captureOutput: false,
32
+ throwOnError: true,
33
+ });
34
+ return { success: true };
35
+ }
36
+ catch (error) {
37
+ logger_1.logger.error(`[Merge Reports] Failed to merge reports:`, error);
38
+ return { success: false };
39
+ }
40
+ }
41
+ function extractUrlMappingsFromBlobs(blobDir) {
42
+ const combinedMap = {};
43
+ const files = fs_1.default.readdirSync(blobDir);
44
+ for (const fileName of files.filter((f) => f.endsWith(".zip"))) {
45
+ 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
+ }
54
+ }
55
+ catch (error) {
56
+ logger_1.logger.error(`[Merge Reports] Failed to extract URL mappings from ${fileName}:`, error);
57
+ }
58
+ }
59
+ logger_1.logger.info(`[Merge Reports] Total URL mappings: ${Object.keys(combinedMap).length}`);
60
+ return combinedMap;
61
+ }
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
+ async function uploadMergedReports(cwd, outputDir, uploadOptions) {
145
+ const { projectName, runId, baseUrl, uploadBucket } = uploadOptions;
146
+ const destinationDir = path_1.default.join(projectName, runId);
147
+ const htmlFilePath = path_1.default.join(outputDir, "index.html");
148
+ const jsonFilePath = path_1.default.join(cwd, "summary.json");
149
+ if (fs_1.default.existsSync(htmlFilePath)) {
150
+ logger_1.logger.debug(`[Merge Reports] Uploading HTML report`);
151
+ const task = (0, r2_uploader_1.createUploadTask)({
152
+ sourceDir: outputDir,
153
+ fileList: [htmlFilePath],
154
+ destinationDir,
155
+ uploadBucket,
156
+ baseUrl,
157
+ });
158
+ void (0, r2_uploader_1.sendTaskToQueue)(task);
159
+ }
160
+ if (fs_1.default.existsSync(jsonFilePath)) {
161
+ logger_1.logger.debug(`[Merge Reports] Uploading summary.json`);
162
+ const task = (0, r2_uploader_1.createUploadTask)({
163
+ sourceDir: cwd,
164
+ fileList: [jsonFilePath],
165
+ destinationDir,
166
+ uploadBucket,
167
+ baseUrl,
168
+ });
169
+ void (0, r2_uploader_1.sendTaskToQueue)(task);
170
+ }
171
+ const traceDir = path_1.default.join(outputDir, "trace");
172
+ if (fs_1.default.existsSync(traceDir)) {
173
+ logger_1.logger.debug(`[Merge Reports] Uploading trace folder`);
174
+ const task = (0, r2_uploader_1.createUploadTask)({
175
+ sourceDir: traceDir,
176
+ destinationDir: path_1.default.join(destinationDir, "trace"),
177
+ uploadBucket,
178
+ baseUrl,
179
+ });
180
+ void (0, r2_uploader_1.sendTaskToQueue)(task);
181
+ }
182
+ await (0, r2_uploader_1.waitForTaskQueueToFinish)();
183
+ const reportUrl = `${baseUrl}/${destinationDir}/index.html`;
184
+ const jsonUrl = `${baseUrl}/${destinationDir}/summary.json`;
185
+ logger_1.logger.info(`[Merge Reports] All uploads completed`);
186
+ logger_1.logger.info(`[Merge Reports] HTML Report: ${reportUrl}`);
187
+ logger_1.logger.info(`[Merge Reports] Summary JSON: ${jsonUrl}`);
188
+ }
189
+ async function mergeReports(options) {
190
+ const cwd = options.cwd || process.cwd();
191
+ const blobDir = options.blobDir || path_1.default.join(cwd, "blob-report");
192
+ const outputDir = path_1.default.join(cwd, "playwright-report");
193
+ const projectName = process.env.PROJECT_NAME;
194
+ const runId = process.env.TEST_RUN_GITHUB_ACTION_ID;
195
+ if (!projectName || !runId) {
196
+ logger_1.logger.error(`[Merge Reports] PROJECT_NAME and TEST_RUN_GITHUB_ACTION_ID must be set`);
197
+ return { success: false };
198
+ }
199
+ if (!fs_1.default.existsSync(blobDir)) {
200
+ logger_1.logger.error(`[Merge Reports] Blob directory does not exist: ${blobDir}`);
201
+ return { success: false };
202
+ }
203
+ const urlMappings = extractUrlMappingsFromBlobs(blobDir);
204
+ const { success } = await runPlaywrightMergeReports({
205
+ blobDir,
206
+ outputDir,
207
+ cwd,
208
+ });
209
+ if (!success) {
210
+ return { success: false };
211
+ }
212
+ const htmlFilePath = path_1.default.join(outputDir, "index.html");
213
+ const jsonFilePath = path_1.default.join(cwd, "summary.json");
214
+ await patchMergedHtmlReport(htmlFilePath, urlMappings);
215
+ await patchSummaryJson(jsonFilePath, urlMappings);
216
+ const hasR2Creds = process.env.R2_ACCOUNT_ID &&
217
+ process.env.R2_ACCESS_KEY_ID &&
218
+ process.env.R2_SECRET_ACCESS_KEY;
219
+ if (hasR2Creds) {
220
+ await uploadMergedReports(cwd, outputDir, {
221
+ projectName,
222
+ runId,
223
+ baseUrl: "https://reports.empirical.run",
224
+ uploadBucket: "test-report",
225
+ });
226
+ }
227
+ else {
228
+ logger_1.logger.info(`[Merge Reports] R2 credentials not found, skipping upload`);
229
+ }
230
+ return { success: true };
231
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"run-specific-test.d.ts","sourceRoot":"","sources":["../../src/lib/run-specific-test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAY5D,wBAAsB,mBAAmB,CAAC,EACxC,KAAU,EACV,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,OAAO,GACR,EAAE;IACD,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,YAAY,CAAC,CA0FxB"}
1
+ {"version":3,"file":"run-specific-test.d.ts","sourceRoot":"","sources":["../../src/lib/run-specific-test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAY5D,wBAAsB,mBAAmB,CAAC,EACxC,KAAU,EACV,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,OAAO,GACR,EAAE;IACD,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,YAAY,CAAC,CA2FxB"}
@@ -33,7 +33,7 @@ async function runSpecificTestsCmd({ tests = [], projects, passthroughArgs, plat
33
33
  }
34
34
  }
35
35
  if (!matchingFilePath) {
36
- const suitesPrefix = testCase.suites
36
+ const suitesPrefix = testCase.suites && testCase.suites.length > 0
37
37
  ? `${testCase.suites.join(" > ")} > `
38
38
  : "";
39
39
  const fullTestName = `${suitesPrefix}${testCase.name}`;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stdout-parser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG;IACnD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjD,CA0CA"}
@@ -1,4 +1,4 @@
1
- import { PlaywrightProject } from "@empiricalrun/shared-types";
1
+ import { PlaywrightProject } from "@empiricalrun/shared-types/tool-results";
2
2
  import { Platform } from "../types";
3
3
  export declare function getProjectsFromPlaywrightConfig(platform: Platform, repoDir: string): Promise<PlaywrightProject[]>;
4
4
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAK/D,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAyE9B"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAK5E,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAyE9B"}
@@ -28,7 +28,7 @@ export declare function markTestAsOnly({ sourceFile, parentDescribeNode, testCas
28
28
  testCaseNode: Node;
29
29
  filePath: string;
30
30
  }): Promise<void>;
31
- export declare const filterArrayByGlobMatchersSet: (input: string[], globMatcherSets: string[][]) => string[];
31
+ export { filterArrayByGlobMatchersSet } from "../glob-matcher";
32
32
  export declare function labelTeardownProjects(projectNames: string[], platform: Platform, repoDir: string): Promise<{
33
33
  isTeardown: boolean;
34
34
  correspondingSetupProject: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
@@ -16,10 +16,10 @@ exports.buildRepoName = buildRepoName;
16
16
  exports.getTypescriptTestBlock = getTypescriptTestBlock;
17
17
  const fs_1 = require("fs");
18
18
  const promises_1 = __importDefault(require("fs/promises"));
19
- const minimatch_1 = require("minimatch");
20
19
  const path_1 = __importDefault(require("path"));
21
20
  const ts_morph_1 = require("ts-morph");
22
21
  const util_1 = require("util");
22
+ const glob_matcher_1 = require("../glob-matcher");
23
23
  const cmd_1 = require("../lib/cmd");
24
24
  const types_1 = require("../types");
25
25
  const config_1 = require("./config");
@@ -167,20 +167,8 @@ async function markTestAsOnly({ sourceFile, parentDescribeNode, testCaseNode, fi
167
167
  }
168
168
  await promises_1.default.writeFile(filePath, updatedTestFileContent, "utf-8");
169
169
  }
170
- const filterArrayByGlobMatchersSet = (
171
- // array that needs to be filtered
172
- input,
173
- // set of glob patterns to filter the array sequentially (takes the intersection of all sets)
174
- globMatcherSets) => {
175
- let filteredList = input;
176
- globMatcherSets.forEach((matcherSet) => {
177
- filteredList = filteredList.filter((item) => {
178
- return matcherSet.some((matcherGlob) => (0, minimatch_1.minimatch)(item, matcherGlob));
179
- });
180
- });
181
- return filteredList;
182
- };
183
- exports.filterArrayByGlobMatchersSet = filterArrayByGlobMatchersSet;
170
+ var glob_matcher_2 = require("../glob-matcher");
171
+ Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return glob_matcher_2.filterArrayByGlobMatchersSet; } });
184
172
  async function labelTeardownProjects(projectNames, platform, repoDir) {
185
173
  const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(platform, repoDir);
186
174
  return projectNames.map((projectName) => {
@@ -203,7 +191,7 @@ const generateProjectFilters = async ({ platform, filteringSets, repoDir, }) =>
203
191
  const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(platform, repoDir);
204
192
  const allProjectNames = allProjects.map((project) => project.name);
205
193
  const filters = filteringSets.map((matchingString) => matchingString.split(","));
206
- const filteredProjects = (0, exports.filterArrayByGlobMatchersSet)(allProjectNames, filters);
194
+ const filteredProjects = (0, glob_matcher_1.filterArrayByGlobMatchersSet)(allProjectNames, filters);
207
195
  if (filteredProjects.length === 0) {
208
196
  throw new Error("No projects found in playwright config that matches the filtering criteria");
209
197
  }
package/package.json CHANGED
@@ -1,40 +1,54 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-run",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
7
7
  },
8
8
  "bin": {
9
- "@empiricalrun/test-run": "dist/bin/index.js"
9
+ "@empiricalrun/test-run": "dist/bin/index.js",
10
+ "@empiricalrun/merge-reports": "dist/bin/merge-reports.js"
10
11
  },
11
12
  "main": "dist/index.js",
13
+ "exports": {
14
+ "./glob-matcher": {
15
+ "types": "./dist/glob-matcher.d.ts",
16
+ "default": "./dist/glob-matcher.js"
17
+ },
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ }
22
+ },
12
23
  "repository": {
13
24
  "type": "git",
14
25
  "url": "https://github.com/empirical-run/empirical.git"
15
26
  },
16
27
  "author": "Empirical Team <hey@empirical.run>",
17
28
  "dependencies": {
29
+ "adm-zip": "^0.5.16",
18
30
  "async-retry": "^1.3.3",
19
31
  "commander": "^12.1.0",
20
32
  "console-log-level": "^1.4.1",
21
33
  "dotenv": "^16.4.5",
22
34
  "minimatch": "^10.0.1",
23
- "ts-morph": "^23.0.0"
35
+ "ts-morph": "^23.0.0",
36
+ "@empiricalrun/r2-uploader": "^0.6.0"
24
37
  },
25
38
  "devDependencies": {
39
+ "@playwright/test": "1.53.2",
40
+ "@types/adm-zip": "^0.5.7",
26
41
  "@types/async-retry": "^1.4.8",
27
42
  "@types/console-log-level": "^1.4.5",
28
43
  "@types/node": "^22.5.5",
29
- "@playwright/test": "1.53.2",
30
44
  "memfs": "^4.17.1",
31
- "@empiricalrun/shared-types": "0.10.0"
45
+ "@empiricalrun/shared-types": "0.12.0"
32
46
  },
33
47
  "scripts": {
34
48
  "dev": "tsc --build --watch",
35
49
  "build": "tsc --build",
36
50
  "clean": "tsc --build --clean",
37
- "lint": "eslint .",
51
+ "lint": "biome check --unsafe",
38
52
  "test": "vitest run",
39
53
  "test:watch": "vitest"
40
54
  }
@@ -1 +1 @@
1
- {"root":["./src/dashboard.ts","./src/index.ts","./src/logger.ts","./src/bin/index.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/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/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 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG;IACnD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjD,CA0CA"}
package/eslint.config.mjs DELETED
@@ -1,16 +0,0 @@
1
- import libraryConfig from "../eslint-config/library.mjs";
2
- import tsParser from "@typescript-eslint/parser";
3
-
4
- export default [
5
- ...libraryConfig,
6
- {
7
- files: ["src/**/*.ts", "src/**/*.tsx"],
8
- languageOptions: {
9
- parser: tsParser,
10
- parserOptions: {
11
- project: "./tsconfig.lint.json",
12
- tsconfigRootDir: import.meta.dirname,
13
- },
14
- },
15
- },
16
- ];
File without changes
File without changes