@empiricalrun/test-run 0.14.1 → 0.15.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/bin/commands/run.d.ts.map +1 -1
  3. package/dist/bin/commands/run.js +43 -20
  4. package/dist/dashboard.d.ts +2 -5
  5. package/dist/dashboard.d.ts.map +1 -1
  6. package/dist/dashboard.js +10 -10
  7. package/dist/env-files.d.ts +16 -0
  8. package/dist/env-files.d.ts.map +1 -0
  9. package/dist/env-files.js +139 -0
  10. package/dist/glob-matcher.d.ts +11 -0
  11. package/dist/glob-matcher.d.ts.map +1 -1
  12. package/dist/glob-matcher.js +19 -1
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +6 -12
  16. package/dist/lib/merge-reports/html.d.ts +1 -1
  17. package/dist/lib/merge-reports/html.d.ts.map +1 -1
  18. package/dist/lib/merge-reports/html.js +30 -39
  19. package/dist/lib/merge-reports/index.d.ts.map +1 -1
  20. package/dist/lib/merge-reports/index.js +53 -37
  21. package/dist/lib/merge-reports/json.d.ts.map +1 -1
  22. package/dist/lib/merge-reports/json.js +12 -21
  23. package/dist/lib/run-all-tests.d.ts +2 -3
  24. package/dist/lib/run-all-tests.d.ts.map +1 -1
  25. package/dist/lib/run-all-tests.js +2 -2
  26. package/dist/lib/run-specific-test.d.ts +2 -3
  27. package/dist/lib/run-specific-test.d.ts.map +1 -1
  28. package/dist/lib/run-specific-test.js +2 -3
  29. package/dist/types/index.d.ts +2 -15
  30. package/dist/types/index.d.ts.map +1 -1
  31. package/dist/types/index.js +0 -12
  32. package/dist/utils/config.d.ts +2 -2
  33. package/dist/utils/config.d.ts.map +1 -1
  34. package/dist/utils/config.js +31 -19
  35. package/dist/utils/index.d.ts +8 -5
  36. package/dist/utils/index.d.ts.map +1 -1
  37. package/dist/utils/index.js +17 -10
  38. package/package.json +6 -4
  39. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @empiricalrun/test-run
2
2
 
3
+ ## 0.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c815fc2: feat: use common code to modify html report paths for shard/non-shard
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [c815fc2]
12
+ - @empiricalrun/reporter@0.28.0
13
+
14
+ ## 0.14.2
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [92254ba]
19
+ - @empiricalrun/r2-uploader@0.9.1
20
+
3
21
  ## 0.14.1
4
22
 
5
23
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/bin/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,QAwJlD"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/bin/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,QAsLlD"}
@@ -2,10 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerRunCommand = registerRunCommand;
4
4
  const dashboard_1 = require("../../dashboard");
5
+ const env_files_1 = require("../../env-files");
5
6
  const cmd_1 = require("../../lib/cmd");
6
7
  const run_all_tests_1 = require("../../lib/run-all-tests");
7
8
  const run_specific_test_1 = require("../../lib/run-specific-test");
8
- const types_1 = require("../../types");
9
9
  const utils_1 = require("../../utils");
10
10
  const config_parser_1 = require("../../utils/config-parser");
11
11
  function registerRunCommand(program) {
@@ -70,30 +70,55 @@ function registerRunCommand(program) {
70
70
  ]
71
71
  : undefined);
72
72
  const environmentSlug = process.env.TEST_RUN_ENVIRONMENT || "";
73
- const environmentVariables = await (0, dashboard_1.fetchEnvironmentVariables)();
73
+ const useEnvFilePrecedence = process.env.ENV_FILE_PRECEDENCE === "true";
74
74
  const envOverrides = {};
75
- environmentVariables.forEach((envVar) => {
76
- envOverrides[envVar.name] = envVar.value;
77
- });
78
- if (Object.keys(envOverrides).length > 0) {
79
- console.log(`Loaded environment variables: ${Object.keys(envOverrides).join(", ")}`);
75
+ if (!useEnvFilePrecedence) {
76
+ const environmentVariables = await (0, dashboard_1.fetchEnvironmentVariables)();
77
+ environmentVariables.forEach((envVar) => {
78
+ envOverrides[envVar.name] = envVar.value;
79
+ });
80
+ if (Object.keys(envOverrides).length > 0) {
81
+ console.log(`Loaded environment variables: ${Object.keys(envOverrides).join(", ")}`);
82
+ }
83
+ }
84
+ if (environmentSlug) {
85
+ (0, env_files_1.writeEnvFiles)({
86
+ repoDir,
87
+ envSetup: {
88
+ environments: [
89
+ {
90
+ slug: environmentSlug,
91
+ vars: envOverrides,
92
+ },
93
+ ],
94
+ activeEnvironmentSlug: environmentSlug,
95
+ },
96
+ logger: { info: (msg) => console.log(`[Env Files] ${msg}`) },
97
+ });
80
98
  }
81
- let environmentSpecificProjects = [];
82
- let platform = types_1.Platform.WEB;
99
+ let environmentMatch = [];
100
+ let environmentIgnore = [];
83
101
  try {
84
102
  if (environmentSlug) {
85
- const { environment, build: latestBuild } = await (0, dashboard_1.fetchEnvironmentAndBuild)(projectName, environmentSlug);
86
- platform = environment.platform;
87
- environmentSpecificProjects = environment.playwright_projects;
88
- if (!process.env.BUILD_URL) {
89
- process.env.BUILD_URL = latestBuild?.build_url;
103
+ const environment = await (0, dashboard_1.fetchEnvironment)(projectName, environmentSlug);
104
+ if (environment.playwright_projects_match &&
105
+ environment.playwright_projects_match.length > 0) {
106
+ environmentMatch = environment.playwright_projects_match;
107
+ environmentIgnore = environment.playwright_projects_ignore ?? [];
90
108
  }
91
- const buildUrl = process.env.BUILD_URL;
109
+ }
110
+ const buildUrl = envOverrides.BUILD_URL;
111
+ if (buildUrl) {
92
112
  await (0, utils_1.downloadBuild)(buildUrl);
93
113
  }
94
- const projectFilters = await (0, utils_1.generateProjectFilters)({
95
- platform,
96
- filteringSets: [...options.project, ...environmentSpecificProjects],
114
+ const hasExplicitProjectFilter = options.project.length > 0 &&
115
+ !(options.project.length === 1 && options.project[0] === "*");
116
+ const matchPatterns = hasExplicitProjectFilter || environmentMatch.length === 0
117
+ ? [...options.project, ...environmentMatch]
118
+ : environmentMatch;
119
+ const projectFilters = await (0, utils_1.generateProjectFiltersV2)({
120
+ match: matchPatterns,
121
+ ignore: environmentIgnore,
97
122
  repoDir,
98
123
  });
99
124
  if (options.skipTeardown) {
@@ -106,7 +131,6 @@ function registerRunCommand(program) {
106
131
  tests,
107
132
  projects: projectFilters,
108
133
  passthroughArgs: pwOptions.join(" "),
109
- platform,
110
134
  envOverrides,
111
135
  repoDir,
112
136
  });
@@ -115,7 +139,6 @@ function registerRunCommand(program) {
115
139
  commandToRun = (0, run_all_tests_1.runAllTestsCmd)({
116
140
  projects: projectFilters,
117
141
  passthroughArgs: pwOptions.join(" "),
118
- platform,
119
142
  envOverrides,
120
143
  });
121
144
  }
@@ -1,4 +1,4 @@
1
- import { Build, Environment } from "./types";
1
+ import { Environment } from "./types";
2
2
  export type EnvironmentVariable = {
3
3
  id: number;
4
4
  project_id: number;
@@ -7,9 +7,6 @@ export type EnvironmentVariable = {
7
7
  created_at: string;
8
8
  updated_at: string;
9
9
  };
10
- export declare const fetchEnvironmentAndBuild: (projectName: string, environmentSlug: string) => Promise<{
11
- environment: Environment;
12
- build: Build;
13
- }>;
10
+ export declare const fetchEnvironment: (projectName: string, environmentSlug: string) => Promise<Environment>;
14
11
  export declare const fetchEnvironmentVariables: () => Promise<EnvironmentVariable[]>;
15
12
  //# sourceMappingURL=dashboard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG7C,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,wBAAwB,GACnC,aAAa,MAAM,EACnB,iBAAiB,MAAM,KACtB,OAAO,CAAC;IACT,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC;CACd,CAwDA,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAa,OAAO,CACxD,mBAAmB,EAAE,CAkDtB,CAAC"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,gBAAgB,GAC3B,aAAa,MAAM,EACnB,iBAAiB,MAAM,KACtB,OAAO,CAAC,WAAW,CAyDrB,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAa,OAAO,CACxD,mBAAmB,EAAE,CAkDtB,CAAC"}
package/dist/dashboard.js CHANGED
@@ -3,19 +3,18 @@ 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.fetchEnvironmentVariables = exports.fetchEnvironmentAndBuild = void 0;
6
+ exports.fetchEnvironmentVariables = exports.fetchEnvironment = void 0;
7
7
  const async_retry_1 = __importDefault(require("async-retry"));
8
8
  const utils_1 = require("./utils");
9
9
  const DOMAIN = process.env.DASHBOARD_DOMAIN || "https://dash.empirical.run";
10
- const fetchEnvironmentAndBuild = async (projectName, environmentSlug) => {
10
+ const fetchEnvironment = async (projectName, environmentSlug) => {
11
11
  const projectRepo = (0, utils_1.buildRepoName)(projectName);
12
12
  const data = await (0, async_retry_1.default)(async (bail) => {
13
13
  if (!process.env.EMPIRICALRUN_API_KEY) {
14
- console.error("No API token found. Skipping fetch environment and latest build from dashboard.");
14
+ console.error("No API token found. Skipping fetch environment from dashboard.");
15
15
  return;
16
16
  }
17
- // TODO: This API endpoint is deprecated. We should use the /list endpoint instead.
18
- const resp = await fetch(`${DOMAIN}/api/environments?project_repo_name=${projectRepo}&environment_slug=${environmentSlug}`, {
17
+ const resp = await fetch(`${DOMAIN}/api/environments/list?project_repo_name=${projectRepo}&environment_slug=${environmentSlug}&is_disabled=false`, {
19
18
  method: "GET",
20
19
  headers: {
21
20
  "Content-Type": "application/json",
@@ -28,7 +27,7 @@ const fetchEnvironmentAndBuild = async (projectName, environmentSlug) => {
28
27
  bail(new Error(erroredResponse?.error?.message));
29
28
  return;
30
29
  }
31
- throw new Error(`Failed to fetch environment and latest build from dashboard for project: ${projectRepo} and env slug: ${environmentSlug}`);
30
+ throw new Error(`Failed to fetch environment from dashboard for project: ${projectRepo} and env slug: ${environmentSlug}`);
32
31
  }
33
32
  return (await resp.json());
34
33
  }, {
@@ -37,12 +36,13 @@ const fetchEnvironmentAndBuild = async (projectName, environmentSlug) => {
37
36
  maxTimeout: 60_000,
38
37
  factor: 3,
39
38
  });
40
- if (!data?.data) {
41
- throw new Error(`Failed to fetch environment and latest build from dashboard for project: ${projectRepo} and env slug: ${environmentSlug}.`);
39
+ const environment = data?.data?.environments?.find((env) => env.slug === environmentSlug);
40
+ if (!environment) {
41
+ throw new Error(`Failed to fetch environment from dashboard for project: ${projectRepo} and env slug: ${environmentSlug}.`);
42
42
  }
43
- return data.data;
43
+ return environment;
44
44
  };
45
- exports.fetchEnvironmentAndBuild = fetchEnvironmentAndBuild;
45
+ exports.fetchEnvironment = fetchEnvironment;
46
46
  const fetchEnvironmentVariables = async () => {
47
47
  if (!process.env.EMPIRICALRUN_API_KEY) {
48
48
  return [];
@@ -0,0 +1,16 @@
1
+ export interface EnvFilesLogger {
2
+ info(message: string): void;
3
+ }
4
+ export type EnvSetup = {
5
+ environments: Array<{
6
+ slug: string;
7
+ vars: Record<string, string>;
8
+ }>;
9
+ activeEnvironmentSlug?: string;
10
+ };
11
+ export declare function writeEnvFiles({ repoDir, envSetup, logger, }: {
12
+ repoDir: string;
13
+ envSetup: EnvSetup;
14
+ logger: EnvFilesLogger;
15
+ }): void;
16
+ //# sourceMappingURL=env-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-files.d.ts","sourceRoot":"","sources":["../src/env-files.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,YAAY,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC9B,CAAC,CAAC;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAwDF,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;CACxB,QAoDA"}
@@ -0,0 +1,139 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.writeEnvFiles = writeEnvFiles;
40
+ const dotenv_1 = require("dotenv");
41
+ const fs = __importStar(require("fs"));
42
+ const js_yaml_1 = __importDefault(require("js-yaml"));
43
+ const path = __importStar(require("path"));
44
+ const ENVIRONMENTS_FILE_PATH = ".empiricalrun/ENVIRONMENTS.yaml";
45
+ function parseDotenv(content) {
46
+ return (0, dotenv_1.parse)(content);
47
+ }
48
+ function buildDotenvContent(vars) {
49
+ return Object.entries(vars)
50
+ .map(([k, v]) => {
51
+ if (v.includes("#") || v.includes("\n") || v !== v.trim()) {
52
+ const escaped = v
53
+ .replace(/\\/g, "\\\\")
54
+ .replace(/"/g, '\\"')
55
+ .replace(/\n/g, "\\n");
56
+ return `${k}="${escaped}"`;
57
+ }
58
+ return `${k}=${v}`;
59
+ })
60
+ .join("\n");
61
+ }
62
+ function parseEnvironmentsYaml(value) {
63
+ if (typeof value !== "object" || value === null)
64
+ return null;
65
+ const obj = value;
66
+ if (!("environments" in obj) || !Array.isArray(obj.environments))
67
+ return null;
68
+ const environments = [];
69
+ for (const env of obj.environments) {
70
+ if (typeof env !== "object" || env === null)
71
+ continue;
72
+ const e = env;
73
+ if (typeof e.slug !== "string" || !e.slug.trim())
74
+ continue;
75
+ if (typeof e.name !== "string" || !e.name.trim())
76
+ continue;
77
+ environments.push({
78
+ slug: e.slug,
79
+ name: e.name,
80
+ env_files: Array.isArray(e.env_files)
81
+ ? e.env_files
82
+ : undefined,
83
+ variables: Array.isArray(e.variables)
84
+ ? e.variables
85
+ : undefined,
86
+ });
87
+ }
88
+ return { environments };
89
+ }
90
+ function readEnvironmentsYaml(repoDir) {
91
+ const yamlPath = path.join(repoDir, ENVIRONMENTS_FILE_PATH);
92
+ if (!fs.existsSync(yamlPath))
93
+ return null;
94
+ const content = fs.readFileSync(yamlPath, "utf-8");
95
+ const parsed = js_yaml_1.default.load(content);
96
+ return parseEnvironmentsYaml(parsed);
97
+ }
98
+ function writeEnvFiles({ repoDir, envSetup, logger, }) {
99
+ const yamlConfig = readEnvironmentsYaml(repoDir);
100
+ for (const env of envSetup.environments) {
101
+ const merged = {};
102
+ const yamlEntry = yamlConfig?.environments.find((e) => e.slug.toLowerCase() === env.slug.toLowerCase());
103
+ // 1. Read and merge template files from repo (cascade order)
104
+ if (yamlEntry?.env_files) {
105
+ for (const file of yamlEntry.env_files) {
106
+ const filePath = path.join(repoDir, file);
107
+ if (fs.existsSync(filePath)) {
108
+ const content = fs.readFileSync(filePath, "utf-8");
109
+ Object.assign(merged, parseDotenv(content));
110
+ }
111
+ }
112
+ }
113
+ // 2. Overlay variables from YAML
114
+ if (yamlEntry?.variables) {
115
+ for (const v of yamlEntry.variables) {
116
+ merged[v.name] = v.value;
117
+ }
118
+ }
119
+ // 3. Overlay DB vars (highest precedence)
120
+ Object.assign(merged, env.vars);
121
+ // 4. Write .env.<slug>
122
+ const slug = env.slug.toLowerCase();
123
+ const envFilePath = path.join(repoDir, `.env.${slug}`);
124
+ fs.writeFileSync(envFilePath, buildDotenvContent(merged));
125
+ logger.info(`Wrote ${envFilePath}`);
126
+ }
127
+ // Symlink .env to the active environment
128
+ if (envSetup.activeEnvironmentSlug) {
129
+ const slug = envSetup.activeEnvironmentSlug.toLowerCase();
130
+ const envPath = path.join(repoDir, ".env");
131
+ const target = `.env.${slug}`;
132
+ if (fs.existsSync(envPath)) {
133
+ fs.unlinkSync(envPath);
134
+ }
135
+ fs.symlinkSync(target, envPath);
136
+ logger.info(`Symlinked .env -> ${target}`);
137
+ }
138
+ logger.info(`Wrote .env files for ${envSetup.environments.length} environments`);
139
+ }
@@ -14,4 +14,15 @@ export declare const filterArrayByGlobMatchersSet: (input: string[], globMatcher
14
14
  * @returns Array of project names that match the patterns
15
15
  */
16
16
  export declare const filterProjectsByGlobPatterns: (allProjectNames: string[], patterns: string[]) => string[];
17
+ /**
18
+ * Filters playwright projects using match and ignore patterns.
19
+ * Match patterns are OR'd (project must match any).
20
+ * Ignore patterns are then applied to exclude (project must not match any).
21
+ *
22
+ * @param allProjectNames - Array of all available project names
23
+ * @param match - Array of glob patterns to include (OR'd together)
24
+ * @param ignore - Array of glob patterns to exclude (OR'd together)
25
+ * @returns Array of project names that match
26
+ */
27
+ export declare const filterProjectsByMatchAndIgnore: (allProjectNames: string[], match: string[], ignore: string[]) => string[];
17
28
  //# sourceMappingURL=glob-matcher.d.ts.map
@@ -1 +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"}
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;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B,GACzC,iBAAiB,MAAM,EAAE,EACzB,OAAO,MAAM,EAAE,EACf,QAAQ,MAAM,EAAE,KACf,MAAM,EAYR,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.filterProjectsByGlobPatterns = exports.filterArrayByGlobMatchersSet = void 0;
3
+ exports.filterProjectsByMatchAndIgnore = exports.filterProjectsByGlobPatterns = exports.filterArrayByGlobMatchersSet = void 0;
4
4
  const minimatch_1 = require("minimatch");
5
5
  /**
6
6
  * Filters an array using glob pattern matchers.
@@ -35,3 +35,21 @@ const filterProjectsByGlobPatterns = (allProjectNames, patterns) => {
35
35
  return (0, exports.filterArrayByGlobMatchersSet)(allProjectNames, globMatcherSets);
36
36
  };
37
37
  exports.filterProjectsByGlobPatterns = filterProjectsByGlobPatterns;
38
+ /**
39
+ * Filters playwright projects using match and ignore patterns.
40
+ * Match patterns are OR'd (project must match any).
41
+ * Ignore patterns are then applied to exclude (project must not match any).
42
+ *
43
+ * @param allProjectNames - Array of all available project names
44
+ * @param match - Array of glob patterns to include (OR'd together)
45
+ * @param ignore - Array of glob patterns to exclude (OR'd together)
46
+ * @returns Array of project names that match
47
+ */
48
+ const filterProjectsByMatchAndIgnore = (allProjectNames, match, ignore) => {
49
+ let result = allProjectNames.filter((name) => match.some((pattern) => (0, minimatch_1.minimatch)(name, pattern)));
50
+ if (ignore.length > 0) {
51
+ result = result.filter((name) => !ignore.some((pattern) => (0, minimatch_1.minimatch)(name, pattern)));
52
+ }
53
+ return result;
54
+ };
55
+ exports.filterProjectsByMatchAndIgnore = filterProjectsByMatchAndIgnore;
package/dist/index.d.ts CHANGED
@@ -2,13 +2,13 @@ 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
4
  import { parseTestListOutput } from "./stdout-parser";
5
- import { Platform, TestCase } from "./types";
5
+ import { TestCase } from "./types";
6
6
  import { getProjectsFromPlaywrightConfig } from "./utils/config";
7
- export { getProjectsFromPlaywrightConfig, parseTestListOutput, Platform, runSpecificTestsCmd, spawnCmd, };
7
+ export { getProjectsFromPlaywrightConfig, parseTestListOutput, runSpecificTestsCmd, spawnCmd, };
8
8
  export { type BuildTestListOptions, type BuildTestListResult, buildTestListFromFailedTestRun, type FailedTest, } from "./failed-test-list";
9
9
  export * from "./glob-matcher";
10
10
  export { type CancellationWatcher, startCancellationWatcher, } from "./lib/cancellation-watcher";
11
- export { filterArrayByGlobMatchersSet, generateProjectFilters } from "./utils";
11
+ export { filterArrayByGlobMatchersSet, generateProjectFilters, generateProjectFiltersV2, } from "./utils";
12
12
  export declare function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, stdout, stderr, }: {
13
13
  testName: string;
14
14
  suites: 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,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,8BAA8B,EAC9B,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC;AAC5B,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"}
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,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,+BAA+B,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EACL,+BAA+B,EAC/B,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,GACT,CAAC;AACF,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,8BAA8B,EAC9B,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,KAAK,mBAAmB,EACxB,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,SAAS,CAAC;AAcjB,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,CAmBD;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.startCancellationWatcher = exports.buildTestListFromFailedTestRun = exports.spawnCmd = exports.runSpecificTestsCmd = exports.Platform = exports.parseTestListOutput = exports.getProjectsFromPlaywrightConfig = void 0;
20
+ exports.generateProjectFiltersV2 = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.startCancellationWatcher = exports.buildTestListFromFailedTestRun = exports.spawnCmd = exports.runSpecificTestsCmd = exports.parseTestListOutput = exports.getProjectsFromPlaywrightConfig = void 0;
21
21
  exports.runSingleTest = runSingleTest;
22
22
  exports.listProjectsAndTests = listProjectsAndTests;
23
23
  const fs_1 = __importDefault(require("fs"));
@@ -28,22 +28,17 @@ const run_specific_test_1 = require("./lib/run-specific-test");
28
28
  Object.defineProperty(exports, "runSpecificTestsCmd", { enumerable: true, get: function () { return run_specific_test_1.runSpecificTestsCmd; } });
29
29
  const stdout_parser_1 = require("./stdout-parser");
30
30
  Object.defineProperty(exports, "parseTestListOutput", { enumerable: true, get: function () { return stdout_parser_1.parseTestListOutput; } });
31
- const types_1 = require("./types");
32
- Object.defineProperty(exports, "Platform", { enumerable: true, get: function () { return types_1.Platform; } });
33
- const utils_1 = require("./utils");
34
31
  const config_1 = require("./utils/config");
35
32
  Object.defineProperty(exports, "getProjectsFromPlaywrightConfig", { enumerable: true, get: function () { return config_1.getProjectsFromPlaywrightConfig; } });
36
- // For test-run package, the library entrypoint, we only support web platform
37
- // The bin entrypoint has support for mobile also
38
- const supportedPlatform = types_1.Platform.WEB;
39
33
  var failed_test_list_1 = require("./failed-test-list");
40
34
  Object.defineProperty(exports, "buildTestListFromFailedTestRun", { enumerable: true, get: function () { return failed_test_list_1.buildTestListFromFailedTestRun; } });
41
35
  __exportStar(require("./glob-matcher"), exports);
42
36
  var cancellation_watcher_1 = require("./lib/cancellation-watcher");
43
37
  Object.defineProperty(exports, "startCancellationWatcher", { enumerable: true, get: function () { return cancellation_watcher_1.startCancellationWatcher; } });
44
- var utils_2 = require("./utils");
45
- Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return utils_2.filterArrayByGlobMatchersSet; } });
46
- Object.defineProperty(exports, "generateProjectFilters", { enumerable: true, get: function () { return utils_2.generateProjectFilters; } });
38
+ var utils_1 = require("./utils");
39
+ Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return utils_1.filterArrayByGlobMatchersSet; } });
40
+ Object.defineProperty(exports, "generateProjectFilters", { enumerable: true, get: function () { return utils_1.generateProjectFilters; } });
41
+ Object.defineProperty(exports, "generateProjectFiltersV2", { enumerable: true, get: function () { return utils_1.generateProjectFiltersV2; } });
47
42
  function getSummaryJsonPath(repoDir) {
48
43
  const pathForPlaywright147 = path_1.default.join(repoDir, "playwright-report", "summary.json");
49
44
  const pathForOtherPlaywrightVersions = path_1.default.join(repoDir, "summary.json");
@@ -57,7 +52,6 @@ async function runSingleTest({ testName, suites, filePath, projects, envOverride
57
52
  tests: [{ name: testName, dir: testDir, filePath, suites }],
58
53
  projects,
59
54
  envOverrides,
60
- platform: supportedPlatform,
61
55
  repoDir,
62
56
  });
63
57
  const { hasTestPassed } = await (0, cmd_1.runTestsForCmd)(commandToRun, repoDir, {
@@ -73,7 +67,7 @@ async function runSingleTest({ testName, suites, filePath, projects, envOverride
73
67
  };
74
68
  }
75
69
  async function listProjectsAndTests(repoDir) {
76
- const testRunner = (0, utils_1.getTestRunner)(types_1.Platform.WEB);
70
+ const testRunner = "playwright";
77
71
  const args = [testRunner, "test", "--list"];
78
72
  const { output, code } = await (0, cmd_1.spawnCmd)("npx", args, {
79
73
  cwd: repoDir,
@@ -1,2 +1,2 @@
1
- export declare function patchMergedHtmlReport(htmlFilePath: string, urlMappings: Record<string, string>): Promise<void>;
1
+ export declare function patchMergedHtmlReport(htmlFilePath: string, summaryJsonFilePath: string): Promise<void>;
2
2
  //# sourceMappingURL=html.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/html.ts"],"names":[],"mappings":"AAaA,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,IAAI,CAAC,CAgIf"}
@@ -5,36 +5,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.patchMergedHtmlReport = patchMergedHtmlReport;
7
7
  const zip_1 = require("@empiricalrun/r2-uploader/zip");
8
+ const reporter_1 = require("@empiricalrun/reporter");
8
9
  const fs_1 = __importDefault(require("fs"));
9
10
  const path_1 = __importDefault(require("path"));
10
11
  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
- }
12
+ async function patchMergedHtmlReport(htmlFilePath, summaryJsonFilePath) {
13
+ let summaryContent;
14
+ try {
15
+ summaryContent = await fs_1.default.promises.readFile(summaryJsonFilePath, "utf8");
16
+ }
17
+ catch (error) {
18
+ logger_1.logger.error(`[Merge Reports] Failed to read summary.json:`, error);
19
+ return;
20
+ }
21
+ const summaryJson = JSON.parse(summaryContent);
22
+ const attachmentMap = (0, reporter_1.buildTestAttachmentMap)(summaryJson, {
23
+ transformAttachment: (attachment) => {
24
+ // Ensure attachment.name includes a file extension so that
25
+ // Playwright's downloadFileNameForAttachment() uses it as-is
26
+ // instead of parsing the (now URL) path for an extension.
27
+ if (attachment.path && !attachment.name.includes(".")) {
28
+ const ext = attachment.path.match(/\.[^/.]+$/)?.[0];
29
+ if (ext) {
30
+ return { ...attachment, name: attachment.name + ext };
29
31
  }
30
32
  }
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`);
33
+ return attachment;
34
+ },
35
+ });
36
+ if (attachmentMap.size === 0) {
37
+ logger_1.logger.debug(`[Merge Reports] No attachments found in summary.json`);
38
38
  return;
39
39
  }
40
40
  let htmlContent;
@@ -66,30 +66,21 @@ async function patchMergedHtmlReport(htmlFilePath, urlMappings) {
66
66
  await fs_1.default.promises.unlink(zipPath);
67
67
  logger_1.logger.info(`[Merge Reports] Zip extracted in ${Date.now() - stepTime}ms`);
68
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);
69
+ logger_1.logger.info(`[Merge Reports] Patching ${jsonFiles.length} JSON files using summary.json attachment map`);
71
70
  stepTime = Date.now();
72
- let totalPatchCount = 0;
73
71
  const patchResults = await Promise.allSettled(jsonFiles.map(async (file) => {
74
72
  const filePath = path_1.default.join(tempDir, file);
75
73
  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;
74
+ const reportJson = JSON.parse(content);
75
+ (0, reporter_1.replaceMediaPaths)(reportJson, attachmentMap);
76
+ await fs_1.default.promises.writeFile(filePath, JSON.stringify(reportJson), "utf8");
83
77
  }));
84
78
  for (const result of patchResults) {
85
79
  if (result.status === "rejected") {
86
80
  logger_1.logger.error(`[Merge Reports] Failed to patch JSON file:`, result.reason);
87
81
  }
88
- else {
89
- totalPatchCount += result.value;
90
- }
91
82
  }
92
- logger_1.logger.info(`[Merge Reports] JSON patching completed in ${Date.now() - stepTime}ms (${totalPatchCount} paths patched)`);
83
+ logger_1.logger.info(`[Merge Reports] JSON patching completed in ${Date.now() - stepTime}ms`);
93
84
  stepTime = Date.now();
94
85
  const newBuffer = await (0, zip_1.createZipFromDirectory)(tempDir);
95
86
  const newBase64 = newBuffer.toString("base64");
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/index.ts"],"names":[],"mappings":"AAcA,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;AA0DlE,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,CAsDf;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,CA4DhC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/index.ts"],"names":[],"mappings":"AAcA,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;AA0DlE,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,CAsDf;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,CA+EhC"}
@@ -166,44 +166,60 @@ async function mergeReports(options) {
166
166
  const outputDir = path_1.default.join(cwd, "playwright-report");
167
167
  const projectName = process.env.PROJECT_NAME;
168
168
  const runId = process.env.TEST_RUN_GITHUB_ACTION_ID;
169
- if (!projectName || !runId) {
170
- logger_1.logger.error(`[Merge Reports] PROJECT_NAME and TEST_RUN_GITHUB_ACTION_ID must be set`);
171
- return { success: false };
172
- }
173
- if (!fs_1.default.existsSync(blobDir)) {
174
- logger_1.logger.error(`[Merge Reports] Blob directory does not exist: ${blobDir}`);
175
- return { success: false };
176
- }
177
- const urlMappings = await extractUrlMappingsFromBlobs(blobDir);
178
- const { success } = await runPlaywrightMergeReports({
179
- blobDir,
180
- outputDir,
181
- cwd,
182
- });
183
- if (!success) {
184
- return { success: false };
185
- }
186
- const htmlFilePath = path_1.default.join(outputDir, "index.html");
187
- const jsonFilePath = path_1.default.join(cwd, "summary.json");
188
- await Promise.all([
189
- (0, html_1.patchMergedHtmlReport)(htmlFilePath, urlMappings),
190
- (0, json_1.patchSummaryJson)(jsonFilePath, urlMappings),
191
- ]);
192
- const enableS3 = process.env.ENABLE_S3_UPLOADS === "true";
193
- const credentials = getCredentialsFromEnv(enableS3);
194
- if (credentials) {
195
- const { baseUrl, uploadBucket } = getStorageConfig(enableS3);
196
- await uploadMergedReports(cwd, outputDir, {
197
- projectName,
198
- runId,
199
- baseUrl,
200
- uploadBucket,
201
- credentials,
169
+ // Track peak memory usage
170
+ let peakMemoryMb = 0;
171
+ const memoryInterval = setInterval(() => {
172
+ const currentMemoryMb = process.memoryUsage().heapUsed / 1024 / 1024;
173
+ if (currentMemoryMb > peakMemoryMb) {
174
+ peakMemoryMb = currentMemoryMb;
175
+ }
176
+ }, 100);
177
+ try {
178
+ if (!projectName || !runId) {
179
+ logger_1.logger.error(`[Merge Reports] PROJECT_NAME and TEST_RUN_GITHUB_ACTION_ID must be set`);
180
+ return { success: false };
181
+ }
182
+ if (!fs_1.default.existsSync(blobDir)) {
183
+ logger_1.logger.error(`[Merge Reports] Blob directory does not exist: ${blobDir}`);
184
+ return { success: false };
185
+ }
186
+ const urlMappings = await extractUrlMappingsFromBlobs(blobDir);
187
+ const { success } = await runPlaywrightMergeReports({
188
+ blobDir,
189
+ outputDir,
190
+ cwd,
202
191
  });
192
+ if (!success) {
193
+ return { success: false };
194
+ }
195
+ const htmlFilePath = path_1.default.join(outputDir, "index.html");
196
+ const jsonFilePath = path_1.default.join(cwd, "summary.json");
197
+ // Patch summary.json first (replaces local paths with URLs),
198
+ // then patch the HTML report (reads the patched summary.json to build an attachment map).
199
+ await (0, json_1.patchSummaryJson)(jsonFilePath, urlMappings);
200
+ await (0, html_1.patchMergedHtmlReport)(htmlFilePath, jsonFilePath);
201
+ const enableS3 = process.env.ENABLE_S3_UPLOADS === "true";
202
+ const credentials = getCredentialsFromEnv(enableS3);
203
+ if (credentials) {
204
+ const { baseUrl, uploadBucket } = getStorageConfig(enableS3);
205
+ await uploadMergedReports(cwd, outputDir, {
206
+ projectName,
207
+ runId,
208
+ baseUrl,
209
+ uploadBucket,
210
+ credentials,
211
+ });
212
+ }
213
+ else {
214
+ const storageType = enableS3 ? "S3" : "R2";
215
+ logger_1.logger.info(`[Merge Reports] ${storageType} credentials not found, skipping upload`);
216
+ }
217
+ return { success: true };
203
218
  }
204
- else {
205
- const storageType = enableS3 ? "S3" : "R2";
206
- logger_1.logger.info(`[Merge Reports] ${storageType} credentials not found, skipping upload`);
219
+ finally {
220
+ clearInterval(memoryInterval);
221
+ // Write metadata file for parent process to read
222
+ const metadataPath = path_1.default.join(cwd, "merge-metadata.json");
223
+ fs_1.default.writeFileSync(metadataPath, JSON.stringify({ peakMemoryMb: Math.round(peakMemoryMb) }));
207
224
  }
208
- return { success: true };
209
225
  }
@@ -1 +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"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/lib/merge-reports/json.ts"],"names":[],"mappings":"AAoCA,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAyCf"}
@@ -4,38 +4,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.patchSummaryJson = patchSummaryJson;
7
+ const reporter_1 = require("@empiricalrun/reporter");
7
8
  const fs_1 = __importDefault(require("fs"));
8
9
  const logger_1 = require("../../logger");
9
10
  const types_1 = require("./types");
10
11
  function patchAttachmentPaths(report, urlMap) {
11
12
  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
- }
13
+ (0, reporter_1.traverseJsonReportSuites)(report, (spec) => {
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;
24
23
  }
25
24
  }
26
25
  }
27
26
  }
28
27
  }
29
28
  }
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
- }
29
+ });
39
30
  return patchCount;
40
31
  }
41
32
  async function patchSummaryJson(jsonFilePath, urlMappings) {
@@ -1,9 +1,8 @@
1
- import { CommandToRun, Platform, TestCase } from "../types";
2
- export declare function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides, platform, }: {
1
+ import { CommandToRun, TestCase } from "../types";
2
+ export declare function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides, }: {
3
3
  tests?: TestCase[];
4
4
  projects: string[];
5
5
  passthroughArgs?: string;
6
- platform: Platform;
7
6
  filesFilter?: string;
8
7
  envOverrides?: Record<string, string>;
9
8
  patternsToGrep?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"run-all-tests.d.ts","sourceRoot":"","sources":["../../src/lib/run-all-tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQ5D,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,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,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GAAG,YAAY,CAsBf"}
1
+ {"version":3,"file":"run-all-tests.d.ts","sourceRoot":"","sources":["../../src/lib/run-all-tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQlD,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,GACb,EAAE;IACD,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GAAG,YAAY,CAsBf"}
@@ -6,8 +6,8 @@ const cmd_1 = require("./cmd");
6
6
  function normalizeSpaces(command) {
7
7
  return command.trim().replace(/ +/g, " ");
8
8
  }
9
- function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides, platform, }) {
10
- const testRunner = (0, utils_1.getTestRunner)(platform);
9
+ function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides, }) {
10
+ const testRunner = (0, utils_1.getTestRunner)();
11
11
  const projectsArg = (projects || [])
12
12
  .map((project) => `--project ${project}`)
13
13
  .join(" ");
@@ -1,9 +1,8 @@
1
- import { CommandToRun, Platform, TestCase } from "../types";
2
- export declare function runSpecificTestsCmd({ tests, projects, passthroughArgs, platform, envOverrides, repoDir, }: {
1
+ import { CommandToRun, TestCase } from "../types";
2
+ export declare function runSpecificTestsCmd({ tests, projects, passthroughArgs, envOverrides, repoDir, }: {
3
3
  tests?: TestCase[];
4
4
  projects: string[];
5
5
  passthroughArgs?: string;
6
- platform: Platform;
7
6
  filesFilter?: string;
8
7
  envOverrides?: Record<string, string>;
9
8
  repoDir: string;
@@ -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,CA2FxB"}
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,MAAM,UAAU,CAAC;AAYlD,wBAAsB,mBAAmB,CAAC,EACxC,KAAU,EACV,QAAQ,EACR,eAAe,EACf,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,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,CAsFxB"}
@@ -7,7 +7,7 @@ exports.runSpecificTestsCmd = runSpecificTestsCmd;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const utils_1 = require("../utils");
9
9
  const run_all_tests_1 = require("./run-all-tests");
10
- async function runSpecificTestsCmd({ tests = [], projects, passthroughArgs, platform, envOverrides, repoDir, }) {
10
+ async function runSpecificTestsCmd({ tests = [], projects, passthroughArgs, envOverrides, repoDir, }) {
11
11
  if (!tests || tests.length === 0) {
12
12
  throw new Error("No tests found");
13
13
  }
@@ -63,7 +63,7 @@ async function runSpecificTestsCmd({ tests = [], projects, passthroughArgs, plat
63
63
  }
64
64
  }
65
65
  }
66
- const teardownLabels = await (0, utils_1.labelTeardownProjects)(projects, platform, repoDir);
66
+ const teardownLabels = await (0, utils_1.labelTeardownProjects)(projects, repoDir);
67
67
  const isRunningForTeardownProjectOnly = teardownLabels && teardownLabels.every((label) => label.isTeardown);
68
68
  if (isRunningForTeardownProjectOnly) {
69
69
  // To run teardown projects, we need to run the `setup` project first, and playwright runs
@@ -81,7 +81,6 @@ async function runSpecificTestsCmd({ tests = [], projects, passthroughArgs, plat
81
81
  passthroughArgs,
82
82
  projects,
83
83
  envOverrides,
84
- platform,
85
84
  patternsToGrep,
86
85
  });
87
86
  return commandToRun;
@@ -11,26 +11,13 @@ export type Environment = {
11
11
  id: number;
12
12
  project_id: number;
13
13
  slug: string;
14
- playwright_projects: string[];
15
- platform: Platform;
16
- };
17
- export type Build = {
18
- id: number;
19
- build_url: string;
14
+ playwright_projects_match?: string[];
15
+ playwright_projects_ignore?: string[];
20
16
  };
21
17
  export type PartialPackageJSON = {
22
18
  name: string;
23
19
  scripts: Record<string, string>;
24
20
  };
25
- export declare enum Platform {
26
- WEB = "web",
27
- ANDROID = "android",
28
- IOS = "ios"
29
- }
30
- export declare enum TestFramework {
31
- PLAYWRIGHT = "playwright",
32
- APPWRIGHT = "appwright"
33
- }
34
21
  export type PlaywProjectConfig = {
35
22
  name: string;
36
23
  teardown?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,oBAAY,QAAQ;IAClB,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,GAAG,QAAQ;CACZ;AAED,oBAAY,aAAa;IACvB,UAAU,eAAe;IACzB,SAAS,cAAc;CACxB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB,CAAC,EAAE,MAAM,EAAE,CAAC;IACrC,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC"}
@@ -1,14 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TestFramework = exports.Platform = void 0;
4
- var Platform;
5
- (function (Platform) {
6
- Platform["WEB"] = "web";
7
- Platform["ANDROID"] = "android";
8
- Platform["IOS"] = "ios";
9
- })(Platform || (exports.Platform = Platform = {}));
10
- var TestFramework;
11
- (function (TestFramework) {
12
- TestFramework["PLAYWRIGHT"] = "playwright";
13
- TestFramework["APPWRIGHT"] = "appwright";
14
- })(TestFramework || (exports.TestFramework = TestFramework = {}));
@@ -1,4 +1,4 @@
1
1
  import { PlaywrightProject } from "@empiricalrun/shared-types/tool-results";
2
- import { Platform } from "../types";
3
- export declare function getProjectsFromPlaywrightConfig(platform: Platform, repoDir: string): Promise<PlaywrightProject[]>;
2
+ export declare function parseProjectsFromOutput(result: string): PlaywrightProject[];
3
+ export declare function getProjectsFromPlaywrightConfig(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,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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAK5E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAwB3E;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA4D9B"}
@@ -3,13 +3,36 @@ 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.parseProjectsFromOutput = parseProjectsFromOutput;
6
7
  exports.getProjectsFromPlaywrightConfig = getProjectsFromPlaywrightConfig;
7
8
  const child_process_1 = require("child_process");
8
9
  const fs_1 = __importDefault(require("fs"));
9
10
  const path_1 = __importDefault(require("path"));
10
- const types_1 = require("../types");
11
- async function getProjectsFromPlaywrightConfig(platform, repoDir) {
12
- const configName = platform === types_1.Platform.WEB ? "playwright.config.ts" : "appwright.config.ts";
11
+ function parseProjectsFromOutput(result) {
12
+ // Extract JSON from between markers to ignore noisy stdout from npx/ts-node
13
+ const markerStart = "___PROJECTS_JSON_START___";
14
+ const markerEnd = "___PROJECTS_JSON_END___";
15
+ const startIdx = result.indexOf(markerStart);
16
+ const endIdx = result.indexOf(markerEnd);
17
+ const jsonStr = startIdx !== -1 && endIdx !== -1
18
+ ? result.substring(startIdx + markerStart.length, endIdx)
19
+ : result;
20
+ // Custom deserializer that reconstructs regex objects
21
+ return JSON.parse(jsonStr, (key, value) => {
22
+ if (value && typeof value === "object") {
23
+ if (value.__regex) {
24
+ return new RegExp(value.source, value.flags);
25
+ }
26
+ if (value.__function) {
27
+ // Note: Functions can't be fully reconstructed, but we preserve the source
28
+ return value.source;
29
+ }
30
+ }
31
+ return value;
32
+ });
33
+ }
34
+ async function getProjectsFromPlaywrightConfig(repoDir) {
35
+ const configName = "playwright.config.ts";
13
36
  try {
14
37
  const configPath = path_1.default.join(repoDir, configName);
15
38
  const tmpScriptPath = path_1.default.join(repoDir, "temp-extract-projects.js");
@@ -34,14 +57,16 @@ async function getProjectsFromPlaywrightConfig(platform, repoDir) {
34
57
  });
35
58
  }
36
59
 
60
+ const MARKER_START = '___PROJECTS_JSON_START___';
61
+ const MARKER_END = '___PROJECTS_JSON_END___';
37
62
  try {
38
63
  // Import the config directly with the full path
39
64
  const configModule = require('${configPath.replace(/\\/g, "\\\\")}');
40
65
  const projects = configModule.default?.projects || configModule.projects || [];
41
- console.log(serializeWithSpecialTypes(projects));
66
+ console.log(MARKER_START + serializeWithSpecialTypes(projects) + MARKER_END);
42
67
  } catch (error) {
43
68
  console.error('Error loading config:', error.message);
44
- console.log('[]'); // Return empty array on error
69
+ console.log(MARKER_START + '[]' + MARKER_END); // Return empty array on error
45
70
  }
46
71
  `);
47
72
  const result = (0, child_process_1.execSync)(`npx -y ts-node@latest "${tmpScriptPath}"`, {
@@ -54,20 +79,7 @@ async function getProjectsFromPlaywrightConfig(platform, repoDir) {
54
79
  cwd: repoDir,
55
80
  });
56
81
  fs_1.default.unlinkSync(tmpScriptPath);
57
- // Custom deserializer that reconstructs regex objects
58
- const projects = JSON.parse(result, (key, value) => {
59
- if (value && typeof value === "object") {
60
- if (value.__regex) {
61
- return new RegExp(value.source, value.flags);
62
- }
63
- if (value.__function) {
64
- // Note: Functions can't be fully reconstructed, but we preserve the source
65
- return value.source;
66
- }
67
- }
68
- return value;
69
- });
70
- return projects;
82
+ return parseProjectsFromOutput(result);
71
83
  }
72
84
  catch (error) {
73
85
  console.error("Error extracting Playwright projects:", error);
@@ -1,5 +1,4 @@
1
1
  import { Node, SourceFile } from "ts-morph";
2
- import { Platform, TestFramework } from "../types";
3
2
  export declare function getAllFilePaths(directoryPath: string | undefined, repoDir: string, filters?: {
4
3
  filePath?: string;
5
4
  }): Promise<string[]>;
@@ -29,19 +28,23 @@ export declare function markTestAsOnly({ sourceFile, parentDescribeNode, testCas
29
28
  filePath: string;
30
29
  }): Promise<void>;
31
30
  export { filterArrayByGlobMatchersSet } from "../glob-matcher";
32
- export declare function labelTeardownProjects(projectNames: string[], platform: Platform, repoDir: string): Promise<{
31
+ export declare function labelTeardownProjects(projectNames: string[], repoDir: string): Promise<{
33
32
  isTeardown: boolean;
34
33
  correspondingSetupProject: string | undefined;
35
34
  }[]>;
36
- export declare const generateProjectFilters: ({ platform, filteringSets, repoDir, }: {
37
- platform: Platform;
35
+ export declare const generateProjectFilters: ({ filteringSets, repoDir, }: {
38
36
  filteringSets: string[];
39
37
  repoDir: string;
40
38
  }) => Promise<string[]>;
39
+ export declare const generateProjectFiltersV2: ({ match, ignore, repoDir, }: {
40
+ match: string[];
41
+ ignore: string[];
42
+ repoDir: string;
43
+ }) => Promise<string[]>;
41
44
  export declare function buildRepoName(projectName: string): string;
42
45
  export declare const pickNameFromPackageJson: () => Promise<string | undefined>;
43
46
  export declare const downloadBuild: (buildUrl: string) => Promise<void>;
44
- export declare const getTestRunner: (platform: Platform) => TestFramework;
47
+ export declare const getTestRunner: () => string;
45
48
  export declare const handleTeardownSkipFlag: (directory: string, repoDir: string) => Promise<void>;
46
49
  /**
47
50
  * function to get the test block and test node for the scenario
@@ -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":"AAGA,OAAO,EAAE,IAAI,EAAW,UAAU,EAAc,MAAM,UAAU,CAAC;AAWjE,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,YAAU,EAC/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BnB;AAED,eAAO,MAAM,gCAAgC,GAC3C,YAAY,UAAU,KACrB,MAgBF,CAAC;AAEF,wBAAsB,eAAe,CAAC,EACpC,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC,CAStE;AAED,wBAAsB,YAAY,CAAC,EACjC,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CAQnB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAWnE;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,IAAI,GAAG,SAAS,GACrB,IAAI,GAAG,SAAS,CA2BlB;AAED,wBAAsB,0CAA0C,CAC9D,QAAQ,EAAE,MAAM,oBA+BjB;AAED,wBAAsB,cAAc,CAAC,EACnC,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACtC,YAAY,EAAE,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAgBA;AAED,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE/D,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,EAAE,MAAM,GACd,OAAO,CACR;IACE,UAAU,EAAE,OAAO,CAAC;IACpB,yBAAyB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C,EAAE,CACJ,CAkBA;AAED,eAAO,MAAM,sBAAsB,GAAU,6BAG1C;IACD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB,KAAG,OAAO,CAAC,MAAM,EAAE,CAgBnB,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,6BAI5C;IACD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,KAAG,OAAO,CAAC,MAAM,EAAE,CAgBnB,CAAC;AAEF,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,eAAO,MAAM,uBAAuB,QAAa,OAAO,CACtD,MAAM,GAAG,SAAS,CAMnB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAclE,CAAC;AAEF,eAAO,MAAM,aAAa,QAAO,MAEhC,CAAC;AAqEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,EACjB,SAAS,MAAM,kBAmBhB,CAAC;AA0BF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,YAAY,EACZ,MAAM,EACN,OAAO,EACP,OAAO,GACR,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG;IACF,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,IAAI,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;CACxB,CAiDA"}
@@ -3,7 +3,7 @@ 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.handleTeardownSkipFlag = exports.getTestRunner = exports.downloadBuild = exports.pickNameFromPackageJson = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.getTestModuleAliasFromSourceFile = void 0;
6
+ exports.handleTeardownSkipFlag = exports.getTestRunner = exports.downloadBuild = exports.pickNameFromPackageJson = exports.generateProjectFiltersV2 = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.getTestModuleAliasFromSourceFile = void 0;
7
7
  exports.getAllFilePaths = getAllFilePaths;
8
8
  exports.getTestCaseNode = getTestCaseNode;
9
9
  exports.hasTestBlock = hasTestBlock;
@@ -21,7 +21,6 @@ const ts_morph_1 = require("ts-morph");
21
21
  const util_1 = require("util");
22
22
  const glob_matcher_1 = require("../glob-matcher");
23
23
  const cmd_1 = require("../lib/cmd");
24
- const types_1 = require("../types");
25
24
  const config_1 = require("./config");
26
25
  async function getAllFilePaths(directoryPath = "tests", repoDir, filters = {}) {
27
26
  let filePaths = [];
@@ -169,8 +168,8 @@ async function markTestAsOnly({ sourceFile, parentDescribeNode, testCaseNode, fi
169
168
  }
170
169
  var glob_matcher_2 = require("../glob-matcher");
171
170
  Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return glob_matcher_2.filterArrayByGlobMatchersSet; } });
172
- async function labelTeardownProjects(projectNames, platform, repoDir) {
173
- const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(platform, repoDir);
171
+ async function labelTeardownProjects(projectNames, repoDir) {
172
+ const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(repoDir);
174
173
  return projectNames.map((projectName) => {
175
174
  const setupForTeardown = allProjects.find((p) => p.teardown === projectName);
176
175
  if (setupForTeardown) {
@@ -187,8 +186,8 @@ async function labelTeardownProjects(projectNames, platform, repoDir) {
187
186
  }
188
187
  });
189
188
  }
190
- const generateProjectFilters = async ({ platform, filteringSets, repoDir, }) => {
191
- const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(platform, repoDir);
189
+ const generateProjectFilters = async ({ filteringSets, repoDir, }) => {
190
+ const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(repoDir);
192
191
  const allProjectNames = allProjects.map((project) => project.name);
193
192
  const filters = filteringSets.map((matchingString) => matchingString.split(","));
194
193
  const filteredProjects = (0, glob_matcher_1.filterArrayByGlobMatchersSet)(allProjectNames, filters);
@@ -198,6 +197,16 @@ const generateProjectFilters = async ({ platform, filteringSets, repoDir, }) =>
198
197
  return filteredProjects;
199
198
  };
200
199
  exports.generateProjectFilters = generateProjectFilters;
200
+ const generateProjectFiltersV2 = async ({ match, ignore, repoDir, }) => {
201
+ const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(repoDir);
202
+ const allProjectNames = allProjects.map((project) => project.name);
203
+ const filteredProjects = (0, glob_matcher_1.filterProjectsByMatchAndIgnore)(allProjectNames, match, ignore);
204
+ if (filteredProjects.length === 0) {
205
+ throw new Error("No projects found in playwright config that matches the filtering criteria");
206
+ }
207
+ return filteredProjects;
208
+ };
209
+ exports.generateProjectFiltersV2 = generateProjectFiltersV2;
201
210
  function buildRepoName(projectName) {
202
211
  return `${projectName}-tests`;
203
212
  }
@@ -224,10 +233,8 @@ const downloadBuild = async (buildUrl) => {
224
233
  }
225
234
  };
226
235
  exports.downloadBuild = downloadBuild;
227
- const getTestRunner = (platform) => {
228
- return platform === types_1.Platform.WEB
229
- ? types_1.TestFramework.PLAYWRIGHT
230
- : types_1.TestFramework.APPWRIGHT;
236
+ const getTestRunner = () => {
237
+ return "playwright";
231
238
  };
232
239
  exports.getTestRunner = getTestRunner;
233
240
  const getAllTeardownFiles = async (directory, repoDir) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-run",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -33,18 +33,20 @@
33
33
  "commander": "^12.1.0",
34
34
  "console-log-level": "^1.4.1",
35
35
  "dotenv": "^16.4.5",
36
+ "js-yaml": "^4.1.0",
36
37
  "minimatch": "^10.0.1",
37
38
  "ts-morph": "^23.0.0",
38
- "@empiricalrun/r2-uploader": "^0.9.0",
39
- "@empiricalrun/reporter": "^0.27.0"
39
+ "@empiricalrun/r2-uploader": "^0.9.1",
40
+ "@empiricalrun/reporter": "^0.28.0"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@playwright/test": "1.57.0",
43
44
  "@types/async-retry": "^1.4.8",
45
+ "@types/js-yaml": "^4.0.9",
44
46
  "@types/console-log-level": "^1.4.5",
45
47
  "@types/node": "^22.5.5",
46
48
  "memfs": "^4.17.1",
47
- "@empiricalrun/shared-types": "0.12.0"
49
+ "@empiricalrun/shared-types": "0.12.1"
48
50
  },
49
51
  "scripts": {
50
52
  "dev": "tsc --build --watch",
@@ -1 +1 @@
1
- {"root":["./src/cmd.ts","./src/dashboard.ts","./src/failed-test-list.ts","./src/glob-matcher.ts","./src/index.ts","./src/logger.ts","./src/bin/index.ts","./src/bin/commands/estimate-time-shard.ts","./src/bin/commands/failed-list.ts","./src/bin/commands/merge.ts","./src/bin/commands/optimize-shards.ts","./src/bin/commands/run.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
+ {"root":["./src/cmd.ts","./src/dashboard.ts","./src/env-files.ts","./src/failed-test-list.ts","./src/glob-matcher.ts","./src/index.ts","./src/logger.ts","./src/bin/index.ts","./src/bin/commands/estimate-time-shard.ts","./src/bin/commands/failed-list.ts","./src/bin/commands/merge.ts","./src/bin/commands/optimize-shards.ts","./src/bin/commands/run.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"}