@empiricalrun/test-run 0.16.1 → 0.17.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 +13 -14
- package/dist/bin/index.js +0 -4
- package/dist/dashboard.d.ts +1 -1
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +4 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/lib/cmd.d.ts.map +1 -1
- package/dist/lib/cmd.js +0 -36
- package/dist/lib/merge-reports/index.d.ts +4 -1
- package/dist/lib/merge-reports/index.d.ts.map +1 -1
- package/dist/lib/merge-reports/index.js +17 -9
- package/dist/lib/merge-reports/types.d.ts +1 -1
- package/dist/lib/run-all-tests.d.ts.map +1 -1
- package/dist/lib/run-all-tests.js +11 -5
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -12
- package/package.json +5 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/bin/commands/estimate-time-shard.d.ts +0 -3
- package/dist/bin/commands/estimate-time-shard.d.ts.map +0 -1
- package/dist/bin/commands/estimate-time-shard.js +0 -122
- package/dist/bin/commands/optimize-shards.d.ts +0 -3
- package/dist/bin/commands/optimize-shards.d.ts.map +0 -1
- package/dist/bin/commands/optimize-shards.js +0 -544
- package/dist/lib/cancellation-watcher.d.ts +0 -5
- package/dist/lib/cancellation-watcher.d.ts.map +0 -1
- package/dist/lib/cancellation-watcher.js +0 -49
- package/test-data/blob-report/report-1.zip +0 -0
- package/test-data/blob-report/report-2.zip +0 -0
- package/test-data/expand-serial-fixture/playwright.config.ts +0 -6
- package/test-data/expand-serial-fixture/serial.spec.ts +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @empiricalrun/test-run
|
|
2
2
|
|
|
3
|
+
## 0.17.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 6fb8170: feat: playwright utils upgraded to use new core
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [6fb8170]
|
|
12
|
+
- @empiricalrun/reporter@0.29.0
|
|
13
|
+
|
|
3
14
|
## 0.16.1
|
|
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;AAczC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,QAiLlD"}
|
package/dist/bin/commands/run.js
CHANGED
|
@@ -50,10 +50,6 @@ function registerRunCommand(program) {
|
|
|
50
50
|
...options.project,
|
|
51
51
|
];
|
|
52
52
|
const pwOptions = command.args.filter((arg) => !optionsToStrip.includes(arg));
|
|
53
|
-
const projectName = process.env.PROJECT_NAME || (await (0, utils_1.pickNameFromPackageJson)());
|
|
54
|
-
if (!projectName) {
|
|
55
|
-
throw new Error("Project name is required");
|
|
56
|
-
}
|
|
57
53
|
const directory = options.dir || "tests";
|
|
58
54
|
const suites = options.suites && options.suites.trim() !== ""
|
|
59
55
|
? options.suites?.split(",")
|
|
@@ -70,16 +66,13 @@ function registerRunCommand(program) {
|
|
|
70
66
|
]
|
|
71
67
|
: undefined);
|
|
72
68
|
const environmentSlug = process.env.TEST_RUN_ENVIRONMENT || "";
|
|
73
|
-
const useEnvFilePrecedence = process.env.ENV_FILE_PRECEDENCE === "true";
|
|
74
69
|
const envOverrides = {};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.log(`Loaded environment variables: ${Object.keys(envOverrides).join(", ")}`);
|
|
82
|
-
}
|
|
70
|
+
const environmentVariables = await (0, dashboard_1.fetchEnvironmentVariables)();
|
|
71
|
+
environmentVariables.forEach((envVar) => {
|
|
72
|
+
envOverrides[envVar.name] = envVar.value;
|
|
73
|
+
});
|
|
74
|
+
if (Object.keys(envOverrides).length > 0) {
|
|
75
|
+
console.log(`Loaded environment variables: ${Object.keys(envOverrides).join(", ")}`);
|
|
83
76
|
}
|
|
84
77
|
if (environmentSlug) {
|
|
85
78
|
(0, env_files_1.writeEnvFiles)({
|
|
@@ -100,7 +93,7 @@ function registerRunCommand(program) {
|
|
|
100
93
|
let environmentIgnore = [];
|
|
101
94
|
try {
|
|
102
95
|
if (environmentSlug) {
|
|
103
|
-
const environment = await (0, dashboard_1.fetchEnvironment)(
|
|
96
|
+
const environment = await (0, dashboard_1.fetchEnvironment)(environmentSlug);
|
|
104
97
|
if (environment.playwright_projects_match &&
|
|
105
98
|
environment.playwright_projects_match.length > 0) {
|
|
106
99
|
environmentMatch = environment.playwright_projects_match;
|
|
@@ -124,6 +117,11 @@ function registerRunCommand(program) {
|
|
|
124
117
|
if (options.skipTeardown) {
|
|
125
118
|
await (0, utils_1.handleTeardownSkipFlag)(directory, repoDir);
|
|
126
119
|
}
|
|
120
|
+
const grepTags = process.env.GREP_TAGS
|
|
121
|
+
? process.env.GREP_TAGS.split(",")
|
|
122
|
+
.filter(Boolean)
|
|
123
|
+
.map((tag) => (tag.startsWith("@") ? tag : `@${tag}`))
|
|
124
|
+
: [];
|
|
127
125
|
const hasTestsFilter = tests && tests.length > 0;
|
|
128
126
|
let commandToRun;
|
|
129
127
|
if (hasTestsFilter) {
|
|
@@ -140,6 +138,7 @@ function registerRunCommand(program) {
|
|
|
140
138
|
projects: projectFilters,
|
|
141
139
|
passthroughArgs: pwOptions.join(" "),
|
|
142
140
|
envOverrides,
|
|
141
|
+
patternsToGrep: grepTags.length > 0 ? grepTags : undefined,
|
|
143
142
|
});
|
|
144
143
|
}
|
|
145
144
|
const { hasTestPassed } = await (0, cmd_1.runTestsForCmd)(commandToRun, repoDir);
|
package/dist/bin/index.js
CHANGED
|
@@ -6,10 +6,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
8
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
9
|
-
const estimate_time_shard_1 = require("./commands/estimate-time-shard");
|
|
10
9
|
const failed_list_1 = require("./commands/failed-list");
|
|
11
10
|
const merge_1 = require("./commands/merge");
|
|
12
|
-
const optimize_shards_1 = require("./commands/optimize-shards");
|
|
13
11
|
const run_1 = require("./commands/run");
|
|
14
12
|
dotenv_1.default.config({
|
|
15
13
|
path: [".env.local", ".env"],
|
|
@@ -21,6 +19,4 @@ commander_1.program
|
|
|
21
19
|
(0, run_1.registerRunCommand)(commander_1.program);
|
|
22
20
|
(0, merge_1.registerMergeCommand)(commander_1.program);
|
|
23
21
|
(0, failed_list_1.registerFailedListCommand)(commander_1.program);
|
|
24
|
-
(0, estimate_time_shard_1.registerEstimateTimeShardCommand)(commander_1.program);
|
|
25
|
-
(0, optimize_shards_1.registerOptimizeShardsCommand)(commander_1.program);
|
|
26
22
|
commander_1.program.parse(process.argv);
|
package/dist/dashboard.d.ts
CHANGED
|
@@ -7,6 +7,6 @@ export type EnvironmentVariable = {
|
|
|
7
7
|
created_at: string;
|
|
8
8
|
updated_at: string;
|
|
9
9
|
};
|
|
10
|
-
export declare const fetchEnvironment: (
|
|
10
|
+
export declare const fetchEnvironment: (environmentSlug: string) => Promise<Environment>;
|
|
11
11
|
export declare const fetchEnvironmentVariables: () => Promise<EnvironmentVariable[]>;
|
|
12
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,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,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,iBAAiB,MAAM,KACtB,OAAO,CAAC,WAAW,CAwDrB,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAa,OAAO,CACxD,mBAAmB,EAAE,CAkDtB,CAAC"}
|
package/dist/dashboard.js
CHANGED
|
@@ -5,16 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.fetchEnvironmentVariables = exports.fetchEnvironment = void 0;
|
|
7
7
|
const async_retry_1 = __importDefault(require("async-retry"));
|
|
8
|
-
const utils_1 = require("./utils");
|
|
9
8
|
const DOMAIN = process.env.DASHBOARD_DOMAIN || "https://dash.empirical.run";
|
|
10
|
-
const fetchEnvironment = async (
|
|
11
|
-
const projectRepo = (0, utils_1.buildRepoName)(projectName);
|
|
9
|
+
const fetchEnvironment = async (environmentSlug) => {
|
|
12
10
|
const data = await (0, async_retry_1.default)(async (bail) => {
|
|
13
11
|
if (!process.env.EMPIRICALRUN_API_KEY) {
|
|
14
12
|
console.error("No API token found. Skipping fetch environment from dashboard.");
|
|
15
13
|
return;
|
|
16
14
|
}
|
|
17
|
-
const resp = await fetch(`${DOMAIN}/api/environments/list?
|
|
15
|
+
const resp = await fetch(`${DOMAIN}/api/environments/list?environment_slug=${environmentSlug}&is_disabled=false`, {
|
|
18
16
|
method: "GET",
|
|
19
17
|
headers: {
|
|
20
18
|
"Content-Type": "application/json",
|
|
@@ -27,7 +25,7 @@ const fetchEnvironment = async (projectName, environmentSlug) => {
|
|
|
27
25
|
bail(new Error(erroredResponse?.error?.message));
|
|
28
26
|
return;
|
|
29
27
|
}
|
|
30
|
-
throw new Error(`Failed to fetch environment from dashboard for
|
|
28
|
+
throw new Error(`Failed to fetch environment from dashboard for env slug: ${environmentSlug}`);
|
|
31
29
|
}
|
|
32
30
|
return (await resp.json());
|
|
33
31
|
}, {
|
|
@@ -38,7 +36,7 @@ const fetchEnvironment = async (projectName, environmentSlug) => {
|
|
|
38
36
|
});
|
|
39
37
|
const environment = data?.data?.environments?.find((env) => env.slug === environmentSlug);
|
|
40
38
|
if (!environment) {
|
|
41
|
-
throw new Error(`Failed to fetch environment from dashboard for
|
|
39
|
+
throw new Error(`Failed to fetch environment from dashboard for env slug: ${environmentSlug}.`);
|
|
42
40
|
}
|
|
43
41
|
return environment;
|
|
44
42
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { getProjectsFromPlaywrightConfig } from "./utils/config";
|
|
|
7
7
|
export { getProjectsFromPlaywrightConfig, parseTestListOutput, runSpecificTestsCmd, spawnCmd, };
|
|
8
8
|
export { type BuildTestListOptions, type BuildTestListResult, buildTestList, buildTestListFromFailedTestRun, expandSerialDependencies, getAllTestsForFile, normalizeTestLine, parseTestListLine, type TestList, } from "./failed-test-list";
|
|
9
9
|
export * from "./glob-matcher";
|
|
10
|
-
export { type CancellationWatcher, startCancellationWatcher, } from "./lib/cancellation-watcher";
|
|
11
10
|
export { filterArrayByGlobMatchersSet, generateProjectFilters, generateProjectFiltersV2, } from "./utils";
|
|
12
11
|
export declare function runSingleTest({ testName, suites, filePath, projects, envOverrides, repoDir, stdout, stderr, }: {
|
|
13
12
|
testName: 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,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,aAAa,EACb,8BAA8B,EAC9B,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,QAAQ,GACd,MAAM,oBAAoB,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,
|
|
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,aAAa,EACb,8BAA8B,EAC9B,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,QAAQ,GACd,MAAM,oBAAoB,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,SAAS,CAAC;AAQjB,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.generateProjectFiltersV2 = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.
|
|
20
|
+
exports.generateProjectFiltersV2 = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.parseTestListLine = exports.normalizeTestLine = exports.getAllTestsForFile = exports.expandSerialDependencies = exports.buildTestListFromFailedTestRun = exports.buildTestList = 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"));
|
|
@@ -38,8 +38,6 @@ Object.defineProperty(exports, "getAllTestsForFile", { enumerable: true, get: fu
|
|
|
38
38
|
Object.defineProperty(exports, "normalizeTestLine", { enumerable: true, get: function () { return failed_test_list_1.normalizeTestLine; } });
|
|
39
39
|
Object.defineProperty(exports, "parseTestListLine", { enumerable: true, get: function () { return failed_test_list_1.parseTestListLine; } });
|
|
40
40
|
__exportStar(require("./glob-matcher"), exports);
|
|
41
|
-
var cancellation_watcher_1 = require("./lib/cancellation-watcher");
|
|
42
|
-
Object.defineProperty(exports, "startCancellationWatcher", { enumerable: true, get: function () { return cancellation_watcher_1.startCancellationWatcher; } });
|
|
43
41
|
var utils_1 = require("./utils");
|
|
44
42
|
Object.defineProperty(exports, "filterArrayByGlobMatchersSet", { enumerable: true, get: function () { return utils_1.filterArrayByGlobMatchersSet; } });
|
|
45
43
|
Object.defineProperty(exports, "generateProjectFilters", { enumerable: true, get: function () { return utils_1.generateProjectFilters; } });
|
package/dist/lib/cmd.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/lib/cmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,eAAe,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/lib/cmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,eAAe,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAeA;AAED,wBAAsB,cAAc,CAClC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,YAAY,EACpC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;;;GAqBF;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IACP,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACxC,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiD5C"}
|
package/dist/lib/cmd.js
CHANGED
|
@@ -5,7 +5,6 @@ exports.runTestsForCmd = runTestsForCmd;
|
|
|
5
5
|
exports.spawnCmd = spawnCmd;
|
|
6
6
|
const child_process_1 = require("child_process");
|
|
7
7
|
const logger_1 = require("../logger");
|
|
8
|
-
const cancellation_watcher_1 = require("./cancellation-watcher");
|
|
9
8
|
function getCommandFromString(command) {
|
|
10
9
|
const regex = /[^\s"']+|"([^"]*)"|'([^']*)'/g;
|
|
11
10
|
const matches = command.match(regex) || [];
|
|
@@ -22,37 +21,8 @@ function getCommandFromString(command) {
|
|
|
22
21
|
}
|
|
23
22
|
async function runTestsForCmd({ command, args, env }, cwd, options) {
|
|
24
23
|
logger_1.logger.debug(`Running cmd: ${command} with args: ${args}`);
|
|
25
|
-
const testRunId = process.env.TEST_RUN_GITHUB_ACTION_ID;
|
|
26
|
-
const apiKey = process.env.EMPIRICALRUN_API_KEY;
|
|
27
|
-
console.log(`[CancellationWatcher] Environment: TEST_RUN_GITHUB_ACTION_ID=${testRunId}, EMPIRICALRUN_API_KEY=${apiKey ? "***" : "undefined"}`);
|
|
28
24
|
let hasTestPassed = true;
|
|
29
25
|
let wasCancelled = false;
|
|
30
|
-
let cancellationWatcher;
|
|
31
|
-
let childProcess;
|
|
32
|
-
const cancelHandler = () => {
|
|
33
|
-
wasCancelled = true;
|
|
34
|
-
console.log(`[CancellationWatcher] Cancel handler invoked, killing child process (pid: ${childProcess?.pid})`);
|
|
35
|
-
if (childProcess && !childProcess.killed) {
|
|
36
|
-
// Use SIGTERM for more forceful termination that propagates to child processes
|
|
37
|
-
childProcess.kill("SIGTERM");
|
|
38
|
-
// Also try to kill the process group to ensure Playwright workers are stopped
|
|
39
|
-
if (childProcess.pid) {
|
|
40
|
-
try {
|
|
41
|
-
process.kill(-childProcess.pid, "SIGTERM");
|
|
42
|
-
console.log(`[CancellationWatcher] Sent SIGTERM to process group ${childProcess.pid}`);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
// Process group kill may fail if not a group leader
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
if (testRunId && apiKey) {
|
|
51
|
-
cancellationWatcher = (0, cancellation_watcher_1.startCancellationWatcher)(testRunId, apiKey, cancelHandler);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
console.log("[CancellationWatcher] Not starting watcher - missing testRunId or apiKey");
|
|
55
|
-
}
|
|
56
26
|
try {
|
|
57
27
|
await spawnCmd(command, args, {
|
|
58
28
|
cwd,
|
|
@@ -61,17 +31,11 @@ async function runTestsForCmd({ command, args, env }, cwd, options) {
|
|
|
61
31
|
throwOnError: true,
|
|
62
32
|
stdout: options?.stdout,
|
|
63
33
|
stderr: options?.stderr,
|
|
64
|
-
onSpawn: (proc) => {
|
|
65
|
-
childProcess = proc;
|
|
66
|
-
},
|
|
67
34
|
});
|
|
68
35
|
}
|
|
69
36
|
catch {
|
|
70
37
|
hasTestPassed = false;
|
|
71
38
|
}
|
|
72
|
-
finally {
|
|
73
|
-
cancellationWatcher?.stop();
|
|
74
|
-
}
|
|
75
39
|
return { hasTestPassed, wasCancelled };
|
|
76
40
|
}
|
|
77
41
|
async function spawnCmd(command, args, options) {
|
|
@@ -6,7 +6,10 @@ export declare function runPlaywrightMergeReports(options: MergeReportsOptions):
|
|
|
6
6
|
success: boolean;
|
|
7
7
|
}>;
|
|
8
8
|
export declare function extractUrlMappingsFromBlobs(blobDir: string): Promise<Record<string, string>>;
|
|
9
|
-
export declare function uploadMergedReports(
|
|
9
|
+
export declare function uploadMergedReports({ outputDir, uploadOptions, }: {
|
|
10
|
+
outputDir: string;
|
|
11
|
+
uploadOptions: UploadOptions;
|
|
12
|
+
}): Promise<void>;
|
|
10
13
|
export declare function mergeReports(options: {
|
|
11
14
|
blobDir?: string;
|
|
12
15
|
cwd?: string;
|
|
@@ -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,
|
|
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,CAsC/B;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoCjC;AAED,wBAAsB,mBAAmB,CAAC,EACxC,SAAS,EACT,aAAa,GACd,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,aAAa,CAAC;CAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDhB;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,CAgFhC"}
|
|
@@ -70,7 +70,14 @@ async function runPlaywrightMergeReports(options) {
|
|
|
70
70
|
logger_1.logger.debug(`[Merge Reports] Blob dir: ${blobDir}`);
|
|
71
71
|
logger_1.logger.debug(`[Merge Reports] Output dir: ${outputDir}`);
|
|
72
72
|
try {
|
|
73
|
-
await (0, cmd_1.spawnCmd)("npx", [
|
|
73
|
+
await (0, cmd_1.spawnCmd)("npx", [
|
|
74
|
+
"--yes",
|
|
75
|
+
"playwright@1.58.2",
|
|
76
|
+
"merge-reports",
|
|
77
|
+
blobDir,
|
|
78
|
+
"--reporter",
|
|
79
|
+
"html,json",
|
|
80
|
+
], {
|
|
74
81
|
cwd,
|
|
75
82
|
envOverrides: {
|
|
76
83
|
PLAYWRIGHT_HTML_OPEN: "never",
|
|
@@ -112,9 +119,9 @@ async function extractUrlMappingsFromBlobs(blobDir) {
|
|
|
112
119
|
logger_1.logger.info(`[Merge Reports] Total URL mappings: ${Object.keys(combinedMap).length}`);
|
|
113
120
|
return combinedMap;
|
|
114
121
|
}
|
|
115
|
-
async function uploadMergedReports(
|
|
116
|
-
const {
|
|
117
|
-
const destinationDir = path_1.default.join(
|
|
122
|
+
async function uploadMergedReports({ outputDir, uploadOptions, }) {
|
|
123
|
+
const { projectSlug, runId, baseUrl, uploadBucket, credentials } = uploadOptions;
|
|
124
|
+
const destinationDir = path_1.default.join(projectSlug, runId);
|
|
118
125
|
const htmlFilePath = path_1.default.join(outputDir, "index.html");
|
|
119
126
|
const jsonFilePath = path_1.default.join(outputDir, "summary.json");
|
|
120
127
|
if (fs_1.default.existsSync(htmlFilePath)) {
|
|
@@ -164,7 +171,7 @@ async function mergeReports(options) {
|
|
|
164
171
|
const cwd = options.cwd || process.cwd();
|
|
165
172
|
const blobDir = options.blobDir || path_1.default.join(cwd, "blob-report");
|
|
166
173
|
const outputDir = path_1.default.join(cwd, "playwright-report");
|
|
167
|
-
const
|
|
174
|
+
const projectSlug = process.env.PROJECT_NAME;
|
|
168
175
|
const runId = process.env.TEST_RUN_GITHUB_ACTION_ID;
|
|
169
176
|
// Track peak memory usage
|
|
170
177
|
let peakMemoryMb = 0;
|
|
@@ -175,7 +182,7 @@ async function mergeReports(options) {
|
|
|
175
182
|
}
|
|
176
183
|
}, 100);
|
|
177
184
|
try {
|
|
178
|
-
if (!
|
|
185
|
+
if (!projectSlug || !runId) {
|
|
179
186
|
logger_1.logger.error(`[Merge Reports] PROJECT_NAME and TEST_RUN_GITHUB_ACTION_ID must be set`);
|
|
180
187
|
return { success: false };
|
|
181
188
|
}
|
|
@@ -202,13 +209,14 @@ async function mergeReports(options) {
|
|
|
202
209
|
const credentials = getCredentialsFromEnv(enableS3);
|
|
203
210
|
if (credentials) {
|
|
204
211
|
const { baseUrl, uploadBucket } = getStorageConfig(enableS3);
|
|
205
|
-
|
|
206
|
-
|
|
212
|
+
const options = {
|
|
213
|
+
projectSlug,
|
|
207
214
|
runId,
|
|
208
215
|
baseUrl,
|
|
209
216
|
uploadBucket,
|
|
210
217
|
credentials,
|
|
211
|
-
}
|
|
218
|
+
};
|
|
219
|
+
await uploadMergedReports({ uploadOptions: options, outputDir });
|
|
212
220
|
}
|
|
213
221
|
else {
|
|
214
222
|
const storageType = enableS3 ? "S3" : "R2";
|
|
@@ -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,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,
|
|
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,CAgCf"}
|
|
@@ -11,17 +11,23 @@ function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter
|
|
|
11
11
|
const projectsArg = (projects || [])
|
|
12
12
|
.map((project) => `--project ${project}`)
|
|
13
13
|
.join(" ");
|
|
14
|
-
|
|
15
|
-
.map((pattern) => ` -g "${pattern}"`)
|
|
16
|
-
.join(" ");
|
|
17
|
-
let args = ` ${filesFilter || ""} ${grepArgs} ${projectsArg} ${passthroughArgs || ""}`;
|
|
14
|
+
let args = ` ${filesFilter || ""} ${projectsArg} ${passthroughArgs || ""}`;
|
|
18
15
|
const envVars = Object.assign({ ...process.env, PW_TEST_HTML_REPORT_OPEN: "never" }, envOverrides);
|
|
19
16
|
if (envVars.RUN_PLAYWRIGHT_HEADED === "true") {
|
|
20
17
|
args = `${args} --headed`;
|
|
21
18
|
}
|
|
22
19
|
const testRunCmd = normalizeSpaces(`npx ${testRunner} test ${args}`);
|
|
20
|
+
const parsed = (0, cmd_1.getCommandFromString)(testRunCmd);
|
|
21
|
+
// Multiple `-g` flags collapse to the last one in Playwright's CLI, so OR
|
|
22
|
+
// all patterns into a single regex passed as one `-g` argument. We append
|
|
23
|
+
// this after `getCommandFromString` because that helper re-escapes regex
|
|
24
|
+
// specials inside quoted args, which would clobber the `|` alternation.
|
|
25
|
+
if (patternsToGrep && patternsToGrep.length > 0) {
|
|
26
|
+
const escapedPatterns = patternsToGrep.map((pattern) => pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
27
|
+
parsed.args.push("-g", escapedPatterns.join("|"));
|
|
28
|
+
}
|
|
23
29
|
return {
|
|
24
|
-
...
|
|
30
|
+
...parsed,
|
|
25
31
|
env: envVars,
|
|
26
32
|
};
|
|
27
33
|
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -41,8 +41,6 @@ export declare const generateProjectFiltersV2: ({ match, ignore, repoDir, }: {
|
|
|
41
41
|
ignore: string[];
|
|
42
42
|
repoDir: string;
|
|
43
43
|
}) => Promise<string[]>;
|
|
44
|
-
export declare function buildRepoName(projectName: string): string;
|
|
45
|
-
export declare const pickNameFromPackageJson: () => Promise<string | undefined>;
|
|
46
44
|
export declare const downloadBuild: (buildUrl: string) => Promise<void>;
|
|
47
45
|
export declare const getTestRunner: () => string;
|
|
48
46
|
export declare const handleTeardownSkipFlag: (directory: string, repoDir: string) => Promise<void>;
|
|
@@ -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;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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
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.
|
|
6
|
+
exports.handleTeardownSkipFlag = exports.getTestRunner = exports.downloadBuild = 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;
|
|
@@ -12,7 +12,6 @@ exports.findFirstSerialDescribeBlock = findFirstSerialDescribeBlock;
|
|
|
12
12
|
exports.hasTopLevelDescribeConfigureWithSerialMode = hasTopLevelDescribeConfigureWithSerialMode;
|
|
13
13
|
exports.markTestAsOnly = markTestAsOnly;
|
|
14
14
|
exports.labelTeardownProjects = labelTeardownProjects;
|
|
15
|
-
exports.buildRepoName = buildRepoName;
|
|
16
15
|
exports.getTypescriptTestBlock = getTypescriptTestBlock;
|
|
17
16
|
const fs_1 = require("fs");
|
|
18
17
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
@@ -207,16 +206,6 @@ const generateProjectFiltersV2 = async ({ match, ignore, repoDir, }) => {
|
|
|
207
206
|
return filteredProjects;
|
|
208
207
|
};
|
|
209
208
|
exports.generateProjectFiltersV2 = generateProjectFiltersV2;
|
|
210
|
-
function buildRepoName(projectName) {
|
|
211
|
-
return `${projectName}-tests`;
|
|
212
|
-
}
|
|
213
|
-
const pickNameFromPackageJson = async () => {
|
|
214
|
-
const packageJSONPath = "package.json";
|
|
215
|
-
const packageJsonStr = await promises_1.default.readFile(packageJSONPath, "utf-8");
|
|
216
|
-
const packageJSONData = JSON.parse(packageJsonStr);
|
|
217
|
-
return packageJSONData.name && packageJSONData.name.replace("-tests", "");
|
|
218
|
-
};
|
|
219
|
-
exports.pickNameFromPackageJson = pickNameFromPackageJson;
|
|
220
209
|
const downloadBuild = async (buildUrl) => {
|
|
221
210
|
const packageJSONPath = "package.json";
|
|
222
211
|
const packageJsonStr = await promises_1.default.readFile(packageJSONPath, "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/test-run",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -37,21 +37,21 @@
|
|
|
37
37
|
"minimatch": "^10.0.1",
|
|
38
38
|
"ts-morph": "^23.0.0",
|
|
39
39
|
"@empiricalrun/r2-uploader": "^0.9.1",
|
|
40
|
-
"@empiricalrun/reporter": "^0.
|
|
40
|
+
"@empiricalrun/reporter": "^0.29.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@playwright/test": "1.
|
|
43
|
+
"@playwright/test": "1.60.0",
|
|
44
44
|
"@types/async-retry": "^1.4.8",
|
|
45
45
|
"@types/js-yaml": "^4.0.9",
|
|
46
46
|
"@types/console-log-level": "^1.4.5",
|
|
47
47
|
"@types/node": "^22.5.5",
|
|
48
48
|
"memfs": "^4.17.1",
|
|
49
|
-
"@empiricalrun/shared-types": "0.
|
|
49
|
+
"@empiricalrun/shared-types": "0.13.0"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"dev": "tsc --build --watch",
|
|
53
53
|
"build": "tsc --build",
|
|
54
|
-
"clean": "tsc --build --clean",
|
|
54
|
+
"clean": "rm -rf dist && tsc --build --clean",
|
|
55
55
|
"lint": "biome check --unsafe",
|
|
56
56
|
"test": "vitest run",
|
|
57
57
|
"test:watch": "vitest"
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
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/
|
|
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/failed-list.ts","./src/bin/commands/merge.ts","./src/bin/commands/run.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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"estimate-time-shard.d.ts","sourceRoot":"","sources":["../../../src/bin/commands/estimate-time-shard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6DzC,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,OAAO,QA6HhE"}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerEstimateTimeShardCommand = registerEstimateTimeShardCommand;
|
|
4
|
-
const reporter_1 = require("@empiricalrun/reporter");
|
|
5
|
-
const child_process_1 = require("child_process");
|
|
6
|
-
async function fetchTestHistory(testCaseIds, dashboardUrl) {
|
|
7
|
-
const apiKey = process.env.EMPIRICALRUN_API_KEY;
|
|
8
|
-
if (!apiKey) {
|
|
9
|
-
throw new Error("EMPIRICALRUN_API_KEY environment variable is required");
|
|
10
|
-
}
|
|
11
|
-
const url = `${dashboardUrl}/api/test-cases/history/batch`;
|
|
12
|
-
const response = await fetch(url, {
|
|
13
|
-
method: "POST",
|
|
14
|
-
headers: {
|
|
15
|
-
"Content-Type": "application/json",
|
|
16
|
-
Authorization: `Bearer ${apiKey}`,
|
|
17
|
-
},
|
|
18
|
-
body: JSON.stringify({ test_case_ids: testCaseIds }),
|
|
19
|
-
});
|
|
20
|
-
if (!response.ok) {
|
|
21
|
-
throw new Error(`Failed to fetch test history: ${response.status}`);
|
|
22
|
-
}
|
|
23
|
-
return response.json();
|
|
24
|
-
}
|
|
25
|
-
function calculateEstimatedDuration(history, includeRetries) {
|
|
26
|
-
if (history.length === 0) {
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
const durationField = includeRetries
|
|
30
|
-
? "duration_total"
|
|
31
|
-
: "duration_per_retry";
|
|
32
|
-
const avgDuration = history.reduce((sum, r) => sum + r[durationField], 0) / history.length;
|
|
33
|
-
return avgDuration;
|
|
34
|
-
}
|
|
35
|
-
function registerEstimateTimeShardCommand(program) {
|
|
36
|
-
program
|
|
37
|
-
.command("estimate-time-shard")
|
|
38
|
-
.description("Estimate how long a shard will take based on historical data")
|
|
39
|
-
.requiredOption("--shard <shard>", "Shard identifier in N/M format (e.g., 1/2)")
|
|
40
|
-
.option("--dashboard-url <url>", "Dashboard URL for fetching test history", process.env.DASHBOARD_URL || "https://dash.empirical.run")
|
|
41
|
-
.option("--workers <workers>", "Number of parallel workers", "8")
|
|
42
|
-
.option("--include-retries", "Use total duration including retries (accounts for flakiness)", false)
|
|
43
|
-
.action(async (options) => {
|
|
44
|
-
const { shard, dashboardUrl, includeRetries } = options;
|
|
45
|
-
const workers = parseInt(options.workers, 10);
|
|
46
|
-
const shardMatch = shard.match(/^(\d+)\/(\d+)$/);
|
|
47
|
-
if (!shardMatch) {
|
|
48
|
-
console.error('Invalid shard format. Expected N/M format (e.g., "1/2")');
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
const shardIndex = parseInt(shardMatch[1], 10);
|
|
52
|
-
const totalShards = parseInt(shardMatch[2], 10);
|
|
53
|
-
if (shardIndex < 1 || shardIndex > totalShards) {
|
|
54
|
-
console.error(`Invalid shard index. Must be between 1 and ${totalShards}`);
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
let jsonReport;
|
|
58
|
-
try {
|
|
59
|
-
const output = (0, child_process_1.execSync)(`npx playwright test --shard ${shard} --list --reporter=json`, {
|
|
60
|
-
encoding: "utf-8",
|
|
61
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
62
|
-
});
|
|
63
|
-
jsonReport = JSON.parse(output);
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
if (error.stdout) {
|
|
67
|
-
try {
|
|
68
|
-
jsonReport = JSON.parse(error.stdout);
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
console.error("Failed to parse playwright JSON output:", error.message);
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
console.error("Failed to get test list from playwright:", error.message);
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const flattenedSpecs = (0, reporter_1.getFlattenedTestList)(jsonReport.suites);
|
|
81
|
-
if (flattenedSpecs.length === 0) {
|
|
82
|
-
console.log("No tests found for this shard.");
|
|
83
|
-
process.exit(0);
|
|
84
|
-
}
|
|
85
|
-
const testCaseIds = flattenedSpecs.map((spec) => spec.id);
|
|
86
|
-
let historyResponse;
|
|
87
|
-
try {
|
|
88
|
-
historyResponse = await fetchTestHistory(testCaseIds, dashboardUrl);
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
console.error("Failed to fetch test history:", error.message);
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
let totalEstimatedDuration = 0;
|
|
95
|
-
let testsWithHistory = 0;
|
|
96
|
-
let testsWithoutHistory = 0;
|
|
97
|
-
for (const testId of testCaseIds) {
|
|
98
|
-
const history = historyResponse[testId] || [];
|
|
99
|
-
const estimatedDuration = calculateEstimatedDuration(history, includeRetries);
|
|
100
|
-
if (history.length > 0) {
|
|
101
|
-
testsWithHistory++;
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
testsWithoutHistory++;
|
|
105
|
-
}
|
|
106
|
-
totalEstimatedDuration += estimatedDuration;
|
|
107
|
-
}
|
|
108
|
-
const parallelizedDuration = totalEstimatedDuration / workers;
|
|
109
|
-
const totalSeconds = Math.round(parallelizedDuration / 1000);
|
|
110
|
-
const minutes = Math.floor(totalSeconds / 60);
|
|
111
|
-
const seconds = totalSeconds % 60;
|
|
112
|
-
console.log(JSON.stringify({
|
|
113
|
-
shard,
|
|
114
|
-
totalTests: testCaseIds.length,
|
|
115
|
-
workers,
|
|
116
|
-
testsWithHistory,
|
|
117
|
-
testsWithoutHistory,
|
|
118
|
-
estimatedDurationMs: Math.round(parallelizedDuration),
|
|
119
|
-
estimatedDurationFormatted: `${minutes}m ${seconds}s`,
|
|
120
|
-
}));
|
|
121
|
-
});
|
|
122
|
-
}
|