@empiricalrun/test-run 0.14.2 → 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.
- package/CHANGELOG.md +11 -0
- package/dist/bin/commands/run.d.ts.map +1 -1
- package/dist/bin/commands/run.js +43 -20
- package/dist/dashboard.d.ts +2 -5
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +10 -10
- package/dist/env-files.d.ts +16 -0
- package/dist/env-files.d.ts.map +1 -0
- package/dist/env-files.js +139 -0
- package/dist/glob-matcher.d.ts +11 -0
- package/dist/glob-matcher.d.ts.map +1 -1
- package/dist/glob-matcher.js +19 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -12
- package/dist/lib/merge-reports/html.d.ts +1 -1
- package/dist/lib/merge-reports/html.d.ts.map +1 -1
- package/dist/lib/merge-reports/html.js +30 -39
- package/dist/lib/merge-reports/index.d.ts.map +1 -1
- package/dist/lib/merge-reports/index.js +53 -37
- package/dist/lib/merge-reports/json.d.ts.map +1 -1
- package/dist/lib/merge-reports/json.js +12 -21
- package/dist/lib/run-all-tests.d.ts +2 -3
- package/dist/lib/run-all-tests.d.ts.map +1 -1
- package/dist/lib/run-all-tests.js +2 -2
- package/dist/lib/run-specific-test.d.ts +2 -3
- package/dist/lib/run-specific-test.d.ts.map +1 -1
- package/dist/lib/run-specific-test.js +2 -3
- package/dist/types/index.d.ts +2 -15
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -12
- package/dist/utils/config.d.ts +2 -2
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +31 -19
- package/dist/utils/index.d.ts +8 -5
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +17 -10
- package/package.json +5 -3
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
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
|
+
|
|
3
14
|
## 0.14.2
|
|
4
15
|
|
|
5
16
|
### 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;
|
|
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"}
|
package/dist/bin/commands/run.js
CHANGED
|
@@ -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
|
|
73
|
+
const useEnvFilePrecedence = process.env.ENV_FILE_PRECEDENCE === "true";
|
|
74
74
|
const envOverrides = {};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
82
|
-
let
|
|
99
|
+
let environmentMatch = [];
|
|
100
|
+
let environmentIgnore = [];
|
|
83
101
|
try {
|
|
84
102
|
if (environmentSlug) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
109
|
+
}
|
|
110
|
+
const buildUrl = envOverrides.BUILD_URL;
|
|
111
|
+
if (buildUrl) {
|
|
92
112
|
await (0, utils_1.downloadBuild)(buildUrl);
|
|
93
113
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
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
|
}
|
package/dist/dashboard.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
package/dist/dashboard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,
|
|
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.
|
|
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
|
|
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
|
|
14
|
+
console.error("No API token found. Skipping fetch environment from dashboard.");
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
|
-
|
|
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
|
|
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
|
-
|
|
41
|
-
|
|
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
|
|
43
|
+
return environment;
|
|
44
44
|
};
|
|
45
|
-
exports.
|
|
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
|
+
}
|
package/dist/glob-matcher.d.ts
CHANGED
|
@@ -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"}
|
package/dist/glob-matcher.js
CHANGED
|
@@ -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 {
|
|
5
|
+
import { TestCase } from "./types";
|
|
6
6
|
import { getProjectsFromPlaywrightConfig } from "./utils/config";
|
|
7
|
-
export { getProjectsFromPlaywrightConfig, parseTestListOutput,
|
|
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[];
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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.
|
|
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
|
|
45
|
-
Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return
|
|
46
|
-
Object.defineProperty(exports, "generateProjectFilters", { enumerable: true, get: function () { return
|
|
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 =
|
|
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,
|
|
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":"
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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":"
|
|
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
|
-
|
|
13
|
-
for (const
|
|
14
|
-
for (const
|
|
15
|
-
for (const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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,
|
|
2
|
-
export declare function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides,
|
|
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,
|
|
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,
|
|
10
|
-
const testRunner = (0, utils_1.getTestRunner)(
|
|
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,
|
|
2
|
-
export declare function runSpecificTestsCmd({ tests, projects, passthroughArgs,
|
|
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,
|
|
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,
|
|
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,
|
|
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;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -11,26 +11,13 @@ export type Environment = {
|
|
|
11
11
|
id: number;
|
|
12
12
|
project_id: number;
|
|
13
13
|
slug: string;
|
|
14
|
-
|
|
15
|
-
|
|
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,
|
|
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"}
|
package/dist/types/index.js
CHANGED
|
@@ -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 = {}));
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { PlaywrightProject } from "@empiricalrun/shared-types/tool-results";
|
|
2
|
-
|
|
3
|
-
export declare function getProjectsFromPlaywrightConfig(
|
|
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,
|
|
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"}
|
package/dist/utils/config.js
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
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
|
-
|
|
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);
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -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[],
|
|
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: ({
|
|
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: (
|
|
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":"AAGA,OAAO,EAAE,IAAI,EAAW,UAAU,EAAc,MAAM,UAAU,CAAC;
|
|
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"}
|
package/dist/utils/index.js
CHANGED
|
@@ -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,
|
|
173
|
-
const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(
|
|
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 ({
|
|
191
|
-
const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(
|
|
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 = (
|
|
228
|
-
return
|
|
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.
|
|
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
39
|
"@empiricalrun/r2-uploader": "^0.9.1",
|
|
39
|
-
"@empiricalrun/reporter": "^0.
|
|
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.
|
|
49
|
+
"@empiricalrun/shared-types": "0.12.1"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {
|
|
50
52
|
"dev": "tsc --build --watch",
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -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"}
|