@smoothdeploy/playwright 1.62.1 → 1.63.0-beta-1793966341000
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.
Potentially problematic release.
This version of @smoothdeploy/playwright might be problematic. Click here for more details.
- package/lib/cli/testActions.js +1 -0
- package/lib/common/index.js +44 -75
- package/lib/common/index.js.txt +10 -10
- package/lib/index.js +80 -42
- package/lib/matchers/expect.js +50 -44
- package/lib/matchers/expect.js.txt +3 -3
- package/lib/mcp/test/browserBackend.js +12 -2
- package/lib/program.js +2 -3
- package/lib/runner/index.js +771 -335
- package/lib/runner/index.js.txt +23 -21
- package/lib/transform/babelBundle.js +4 -5
- package/lib/transform/babelBundle.js.txt +2 -2
- package/lib/transform/esmLoader.js +9 -30
- package/lib/transform/esmLoader.js.txt +3 -3
- package/lib/worker/workerProcessEntry.js +26 -13
- package/lib/worker/workerProcessEntry.js.txt +3 -3
- package/package.json +3 -6
- package/types/test.d.ts +237 -11
- package/types/testReporter.d.ts +52 -1
package/lib/runner/index.js
CHANGED
|
@@ -53,9 +53,7 @@ __export(testRunner_exports, {
|
|
|
53
53
|
runAllTestsWithConfig: () => runAllTestsWithConfig
|
|
54
54
|
});
|
|
55
55
|
var import_events2 = __toESM(require("events"));
|
|
56
|
-
var
|
|
57
|
-
var import_path17 = __toESM(require("path"));
|
|
58
|
-
var import_coreBundle2 = require("playwright-core/lib/coreBundle");
|
|
56
|
+
var import_coreBundle3 = require("playwright-core/lib/coreBundle");
|
|
59
57
|
var import_common10 = require("../common");
|
|
60
58
|
|
|
61
59
|
// packages/playwright/src/runner/fsWatcher.ts
|
|
@@ -81,14 +79,21 @@ var FSWatcher = class {
|
|
|
81
79
|
this._throttleTimer = void 0;
|
|
82
80
|
if (!this._watchedPaths.length)
|
|
83
81
|
return;
|
|
84
|
-
const
|
|
82
|
+
const ignoredPrefixes = this._ignoredFolders.map((folder) => folder.replace(/\\/g, "/") + "/");
|
|
83
|
+
const ignored = (file) => {
|
|
84
|
+
if (file.split("/").includes("node_modules"))
|
|
85
|
+
return true;
|
|
86
|
+
return ignoredPrefixes.some((prefix) => (file + "/").startsWith(prefix));
|
|
87
|
+
};
|
|
85
88
|
this._fsWatcher = chokidar.watch(watchedPaths, { ignoreInitial: true, ignored }).on("all", async (event, file) => {
|
|
89
|
+
if (event !== "add" && event !== "addDir" && event !== "change" && event !== "unlink" && event !== "unlinkDir")
|
|
90
|
+
return;
|
|
86
91
|
if (this._throttleTimer)
|
|
87
92
|
clearTimeout(this._throttleTimer);
|
|
88
93
|
this._collector.push({ event, file });
|
|
89
94
|
this._throttleTimer = setTimeout(() => this._reportEventsIfAny(), 250);
|
|
90
95
|
});
|
|
91
|
-
await new Promise((resolve, reject) => this._fsWatcher.once("ready", resolve).once("error", reject));
|
|
96
|
+
await new Promise((resolve, reject) => this._fsWatcher.once("ready", () => resolve()).once("error", reject));
|
|
92
97
|
}
|
|
93
98
|
async close() {
|
|
94
99
|
await this._fsWatcher?.close();
|
|
@@ -498,7 +503,9 @@ var TeleTestStep = class {
|
|
|
498
503
|
this.steps = [];
|
|
499
504
|
this._startTime = 0;
|
|
500
505
|
this.title = payload.title;
|
|
506
|
+
this.subtitle = payload.subtitle;
|
|
501
507
|
this.category = payload.category;
|
|
508
|
+
this.params = payload.params;
|
|
502
509
|
this.location = location;
|
|
503
510
|
this.parent = parentStep;
|
|
504
511
|
this._startTime = payload.startTime;
|
|
@@ -597,7 +604,7 @@ function parseRegexPatterns(patterns) {
|
|
|
597
604
|
}
|
|
598
605
|
function computeTestCaseOutcome(test) {
|
|
599
606
|
let skipped = 0;
|
|
600
|
-
let
|
|
607
|
+
let didNotRun2 = 0;
|
|
601
608
|
let expected = 0;
|
|
602
609
|
let interrupted = 0;
|
|
603
610
|
let unexpected = 0;
|
|
@@ -607,7 +614,7 @@ function computeTestCaseOutcome(test) {
|
|
|
607
614
|
} else if (result.status === "skipped" && test.expectedStatus === "skipped") {
|
|
608
615
|
++skipped;
|
|
609
616
|
} else if (result.status === "skipped") {
|
|
610
|
-
++
|
|
617
|
+
++didNotRun2;
|
|
611
618
|
} else if (result.status === test.expectedStatus) {
|
|
612
619
|
++expected;
|
|
613
620
|
} else {
|
|
@@ -759,7 +766,14 @@ async function gitCommitInfo(gitDir) {
|
|
|
759
766
|
async function gitDiff(gitDir, ci) {
|
|
760
767
|
const diffLimit = 1e5;
|
|
761
768
|
if (ci?.prBaseHash) {
|
|
762
|
-
await runGit(["
|
|
769
|
+
const hasBaseCommit = await runGit(["cat-file", "-e", `${ci.prBaseHash}^{commit}`], gitDir) !== void 0;
|
|
770
|
+
if (!hasBaseCommit) {
|
|
771
|
+
const isShallow = await runGit(["rev-parse", "--is-shallow-repository"], gitDir) === "true";
|
|
772
|
+
const fetchArgs = ["fetch", "origin", ci.prBaseHash, "--no-auto-maintenance", "--no-auto-gc", "--no-tags", "--no-recurse-submodules"];
|
|
773
|
+
if (isShallow)
|
|
774
|
+
fetchArgs.push("--depth=1");
|
|
775
|
+
await runGit(fetchArgs, gitDir);
|
|
776
|
+
}
|
|
763
777
|
const diff3 = await runGit(["diff", ci.prBaseHash, "HEAD"], gitDir);
|
|
764
778
|
if (diff3)
|
|
765
779
|
return diff3.substring(0, diffLimit);
|
|
@@ -1180,7 +1194,7 @@ var TerminalReporter = class {
|
|
|
1180
1194
|
const threshold = this.config.reportSlowTests.threshold;
|
|
1181
1195
|
return fileDurations.filter(([, duration]) => duration > threshold).slice(0, count);
|
|
1182
1196
|
}
|
|
1183
|
-
generateSummaryMessage({ didNotRun, skipped, expected, interrupted, unexpected, flaky, fatalErrors }) {
|
|
1197
|
+
generateSummaryMessage({ didNotRun: didNotRun2, skipped, expected, interrupted, unexpected, flaky, fatalErrors }) {
|
|
1184
1198
|
const tokens = [];
|
|
1185
1199
|
if (unexpected.length) {
|
|
1186
1200
|
tokens.push(this.screen.colors.red(` ${unexpected.length} failed`));
|
|
@@ -1199,8 +1213,8 @@ var TerminalReporter = class {
|
|
|
1199
1213
|
}
|
|
1200
1214
|
if (skipped)
|
|
1201
1215
|
tokens.push(this.screen.colors.yellow(` ${skipped} skipped`));
|
|
1202
|
-
if (
|
|
1203
|
-
tokens.push(this.screen.colors.yellow(` ${
|
|
1216
|
+
if (didNotRun2)
|
|
1217
|
+
tokens.push(this.screen.colors.yellow(` ${didNotRun2} did not run`));
|
|
1204
1218
|
if (expected)
|
|
1205
1219
|
tokens.push(this.screen.colors.green(` ${expected} passed`) + this.screen.colors.dim(` (${msToString(this.result.duration)})`));
|
|
1206
1220
|
if (fatalErrors.length && expected + unexpected.length + interrupted.length + flaky.length > 0)
|
|
@@ -1208,7 +1222,7 @@ var TerminalReporter = class {
|
|
|
1208
1222
|
return tokens.join("\n");
|
|
1209
1223
|
}
|
|
1210
1224
|
generateSummary() {
|
|
1211
|
-
let
|
|
1225
|
+
let didNotRun2 = 0;
|
|
1212
1226
|
let skipped = 0;
|
|
1213
1227
|
let expected = 0;
|
|
1214
1228
|
const interrupted = [];
|
|
@@ -1223,7 +1237,7 @@ var TerminalReporter = class {
|
|
|
1223
1237
|
interruptedToPrint.push(test);
|
|
1224
1238
|
interrupted.push(test);
|
|
1225
1239
|
} else if (!test.results.length || test.expectedStatus !== "skipped") {
|
|
1226
|
-
++
|
|
1240
|
+
++didNotRun2;
|
|
1227
1241
|
} else {
|
|
1228
1242
|
++skipped;
|
|
1229
1243
|
}
|
|
@@ -1242,7 +1256,7 @@ var TerminalReporter = class {
|
|
|
1242
1256
|
});
|
|
1243
1257
|
const failuresToPrint = [...unexpected, ...flaky, ...interruptedToPrint];
|
|
1244
1258
|
return {
|
|
1245
|
-
didNotRun,
|
|
1259
|
+
didNotRun: didNotRun2,
|
|
1246
1260
|
skipped,
|
|
1247
1261
|
expected,
|
|
1248
1262
|
interrupted,
|
|
@@ -1285,7 +1299,7 @@ var TerminalReporter = class {
|
|
|
1285
1299
|
return formatTestTitle(this.screen, this.config, test, step, this._options);
|
|
1286
1300
|
}
|
|
1287
1301
|
formatTestHeader(test, options = {}) {
|
|
1288
|
-
return formatTestHeader(this.screen, this.config, test, { ...options, includeTestId: this._options.includeTestId });
|
|
1302
|
+
return formatTestHeader(this.screen, this.config, test, { ...options, includeTestId: this._options.includeTestId, omitTags: this._options.omitTags });
|
|
1289
1303
|
}
|
|
1290
1304
|
formatFailure(test, index) {
|
|
1291
1305
|
return formatFailure(this.screen, this.config, test, index, this._options);
|
|
@@ -1320,7 +1334,7 @@ function formatFailure(screen, config2, test, index, options) {
|
|
|
1320
1334
|
if (!errors.length)
|
|
1321
1335
|
continue;
|
|
1322
1336
|
if (!printedHeader) {
|
|
1323
|
-
const header = formatTestHeader(screen, config2, test, { indent: " ", index, mode: "error", includeTestId: options?.includeTestId });
|
|
1337
|
+
const header = formatTestHeader(screen, config2, test, { indent: " ", index, mode: "error", includeTestId: options?.includeTestId, omitTags: options?.omitTags });
|
|
1324
1338
|
lines.push(screen.colors.red(header));
|
|
1325
1339
|
printedHeader = true;
|
|
1326
1340
|
}
|
|
@@ -1433,7 +1447,9 @@ function relativeTestPath(screen, config2, test) {
|
|
|
1433
1447
|
return relativeFilePath(screen, config2, test.location.file);
|
|
1434
1448
|
}
|
|
1435
1449
|
function stepSuffix(step) {
|
|
1436
|
-
const stepTitles =
|
|
1450
|
+
const stepTitles = [];
|
|
1451
|
+
for (let current = step; current; current = current.parent)
|
|
1452
|
+
stepTitles.unshift(current.subtitle ? `${current.title} ${current.subtitle}` : current.title);
|
|
1437
1453
|
return stepTitles.map((t2) => t2.split("\n")[0]).map((t2) => " \u203A " + t2).join("");
|
|
1438
1454
|
}
|
|
1439
1455
|
function formatTestTitle(screen, config2, test, step, options = {}) {
|
|
@@ -1443,7 +1459,7 @@ function formatTestTitle(screen, config2, test, step, options = {}) {
|
|
|
1443
1459
|
const projectLabel = options.includeTestId ? `project=` : "";
|
|
1444
1460
|
const projectTitle = projectName ? `[${projectLabel}${projectName}] \u203A ` : "";
|
|
1445
1461
|
const testTitle = `${testId}${projectTitle}${location} \u203A ${titles.join(" \u203A ")}`;
|
|
1446
|
-
const extraTags = test.tags.filter((t2) => !testTitle.includes(t2) && !config2.tags.includes(t2));
|
|
1462
|
+
const extraTags = options.omitTags ? [] : test.tags.filter((t2) => !testTitle.includes(t2) && !config2.tags.includes(t2));
|
|
1447
1463
|
return `${testTitle}${stepSuffix(step)}${extraTags.length ? " " + extraTags.join(" ") : ""}`;
|
|
1448
1464
|
}
|
|
1449
1465
|
function formatTestHeader(screen, config2, test, options = {}) {
|
|
@@ -1859,7 +1875,7 @@ function addLocationAndSnippetToError(config2, error, file) {
|
|
|
1859
1875
|
}
|
|
1860
1876
|
|
|
1861
1877
|
// packages/playwright/src/runner/testRunner.ts
|
|
1862
|
-
var
|
|
1878
|
+
var import_util16 = require("../util");
|
|
1863
1879
|
|
|
1864
1880
|
// packages/playwright/src/runner/reporters.ts
|
|
1865
1881
|
var reporters_exports = {};
|
|
@@ -1867,7 +1883,7 @@ __export(reporters_exports, {
|
|
|
1867
1883
|
createErrorCollectingReporter: () => createErrorCollectingReporter,
|
|
1868
1884
|
createReporters: () => createReporters
|
|
1869
1885
|
});
|
|
1870
|
-
var
|
|
1886
|
+
var import_fs9 = __toESM(require("fs"));
|
|
1871
1887
|
|
|
1872
1888
|
// packages/playwright/src/runner/loadUtils.ts
|
|
1873
1889
|
var import_path4 = __toESM(require("path"));
|
|
@@ -2007,11 +2023,23 @@ var ProcessHost = class extends import_events.EventEmitter {
|
|
|
2007
2023
|
return;
|
|
2008
2024
|
const exitPromise = new Promise((f) => this.once("exit", () => f()));
|
|
2009
2025
|
const timeout = +(process.env.PWTEST_CHILD_PROCESS_TIMEOUT || 5 * 60 * 1e3);
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2026
|
+
let lastHeartbeat = monotonicTime4();
|
|
2027
|
+
const onHeartbeat = () => lastHeartbeat = monotonicTime4();
|
|
2028
|
+
this.on("__heartbeat__", onHeartbeat);
|
|
2029
|
+
try {
|
|
2030
|
+
while (true) {
|
|
2031
|
+
const result = await raceAgainstDeadline2(() => exitPromise, lastHeartbeat + timeout);
|
|
2032
|
+
if (!result.timedOut)
|
|
2033
|
+
return;
|
|
2034
|
+
if (monotonicTime4() < lastHeartbeat + timeout)
|
|
2035
|
+
continue;
|
|
2036
|
+
this.emit("processError", { message: `Error: ${this._processName} process did not exit within ${timeout}ms after stop, force-killed it` });
|
|
2037
|
+
this._forceKill();
|
|
2038
|
+
await exitPromise;
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
} finally {
|
|
2042
|
+
this.off("__heartbeat__", onHeartbeat);
|
|
2015
2043
|
}
|
|
2016
2044
|
}
|
|
2017
2045
|
_forceKill() {
|
|
@@ -2361,7 +2389,8 @@ function createTestGroups(projectSuite, expectedParallelism) {
|
|
|
2361
2389
|
requireFile: test._requireFile,
|
|
2362
2390
|
repeatEachIndex: test.repeatEachIndex,
|
|
2363
2391
|
projectId: test._projectId,
|
|
2364
|
-
tests: []
|
|
2392
|
+
tests: [],
|
|
2393
|
+
locks: []
|
|
2365
2394
|
};
|
|
2366
2395
|
};
|
|
2367
2396
|
for (const test of projectSuite.allTests()) {
|
|
@@ -2421,6 +2450,14 @@ function createTestGroups(projectSuite, expectedParallelism) {
|
|
|
2421
2450
|
}
|
|
2422
2451
|
}
|
|
2423
2452
|
}
|
|
2453
|
+
for (const group of result) {
|
|
2454
|
+
const locks = /* @__PURE__ */ new Set();
|
|
2455
|
+
for (const test of group.tests) {
|
|
2456
|
+
for (const lock of test._locks)
|
|
2457
|
+
locks.add(lock);
|
|
2458
|
+
}
|
|
2459
|
+
group.locks = [...locks];
|
|
2460
|
+
}
|
|
2424
2461
|
return result;
|
|
2425
2462
|
}
|
|
2426
2463
|
function filterForShard(shard, weights, testGroups) {
|
|
@@ -3003,7 +3040,9 @@ var TeleReporterEmitter = class {
|
|
|
3003
3040
|
id: step[this._idSymbol],
|
|
3004
3041
|
parentStepId: step.parent?.[this._idSymbol],
|
|
3005
3042
|
title: step.title,
|
|
3043
|
+
subtitle: step.subtitle,
|
|
3006
3044
|
category: step.category,
|
|
3045
|
+
params: step.params,
|
|
3007
3046
|
startTime: +step.startTime,
|
|
3008
3047
|
location: this._relativeLocation(step.location)
|
|
3009
3048
|
};
|
|
@@ -3136,9 +3175,10 @@ var BlobReporter = class extends TeleReporterEmitter {
|
|
|
3136
3175
|
};
|
|
3137
3176
|
|
|
3138
3177
|
// packages/playwright/src/reporters/dot.ts
|
|
3178
|
+
var { getAsBooleanFromENV } = require("playwright-core/lib/coreBundle").utils;
|
|
3139
3179
|
var DotReporter = class extends TerminalReporter {
|
|
3140
|
-
constructor() {
|
|
3141
|
-
super(...
|
|
3180
|
+
constructor(options) {
|
|
3181
|
+
super({ ...options, omitTags: getAsBooleanFromENV("PLAYWRIGHT_DOT_OMIT_TAGS", options?.omitTags) });
|
|
3142
3182
|
this._counter = 0;
|
|
3143
3183
|
}
|
|
3144
3184
|
onBegin(suite) {
|
|
@@ -3228,6 +3268,7 @@ var import_path7 = __toESM(require("path"));
|
|
|
3228
3268
|
var import_util7 = require("../util");
|
|
3229
3269
|
var { noColors: noColors2 } = require("playwright-core/lib/coreBundle").iso;
|
|
3230
3270
|
var { msToString: msToString2 } = require("playwright-core/lib/coreBundle").iso;
|
|
3271
|
+
var { getAsBooleanFromENV: getAsBooleanFromENV2 } = require("playwright-core/lib/coreBundle").utils;
|
|
3231
3272
|
var GitHubLogger = class {
|
|
3232
3273
|
newLine() {
|
|
3233
3274
|
process.stdout.write("\n");
|
|
@@ -3253,7 +3294,7 @@ var GitHubLogger = class {
|
|
|
3253
3294
|
};
|
|
3254
3295
|
var GitHubReporter = class extends TerminalReporter {
|
|
3255
3296
|
constructor(options = {}) {
|
|
3256
|
-
super(options);
|
|
3297
|
+
super({ ...options, omitTags: getAsBooleanFromENV2("PLAYWRIGHT_GITHUB_OMIT_TAGS", options.omitTags) });
|
|
3257
3298
|
this.githubLogger = new GitHubLogger();
|
|
3258
3299
|
this._failedTestCount = 0;
|
|
3259
3300
|
this.screen = { ...this.screen, colors: noColors2 };
|
|
@@ -3845,6 +3886,7 @@ var HtmlBuilder = class {
|
|
|
3845
3886
|
title = `${title} (skipped${skipped.description ? ": " + skipped.description : ""})`;
|
|
3846
3887
|
const testStep = {
|
|
3847
3888
|
title,
|
|
3889
|
+
subtitle: step.subtitle,
|
|
3848
3890
|
startTime: step.startTime.toISOString(),
|
|
3849
3891
|
duration,
|
|
3850
3892
|
steps: dedupeSteps(step.steps).map((s) => this._createTestStep(s, result)),
|
|
@@ -3930,7 +3972,7 @@ function dedupeSteps(steps) {
|
|
|
3930
3972
|
for (const step of steps) {
|
|
3931
3973
|
const canDedupe = !step.error && step.duration >= 0 && step.location?.file && !step.steps.length;
|
|
3932
3974
|
const lastStep = lastResult?.step;
|
|
3933
|
-
if (canDedupe && lastResult && lastStep && step.category === lastStep.category && step.title === lastStep.title && step.location?.file === lastStep.location?.file && step.location?.line === lastStep.location?.line && step.location?.column === lastStep.location?.column) {
|
|
3975
|
+
if (canDedupe && lastResult && lastStep && step.category === lastStep.category && step.title === lastStep.title && step.subtitle === lastStep.subtitle && step.location?.file === lastStep.location?.file && step.location?.line === lastStep.location?.line && step.location?.column === lastStep.location?.column) {
|
|
3934
3976
|
++lastResult.count;
|
|
3935
3977
|
lastResult.duration += step.duration;
|
|
3936
3978
|
continue;
|
|
@@ -4181,6 +4223,7 @@ var JSONReporter = class {
|
|
|
4181
4223
|
const steps = step.steps.filter((s) => s.category === "test.step");
|
|
4182
4224
|
return {
|
|
4183
4225
|
title: step.title,
|
|
4226
|
+
subtitle: step.subtitle,
|
|
4184
4227
|
duration: step.duration,
|
|
4185
4228
|
error: step.error,
|
|
4186
4229
|
steps: steps.length ? steps.map((s) => this._serializeTestStep(s)) : void 0
|
|
@@ -4215,7 +4258,7 @@ var json_default = JSONReporter;
|
|
|
4215
4258
|
var import_fs7 = __toESM(require("fs"));
|
|
4216
4259
|
var import_path10 = __toESM(require("path"));
|
|
4217
4260
|
var import_util9 = require("../util");
|
|
4218
|
-
var { getAsBooleanFromENV } = require("playwright-core/lib/coreBundle").utils;
|
|
4261
|
+
var { getAsBooleanFromENV: getAsBooleanFromENV3 } = require("playwright-core/lib/coreBundle").utils;
|
|
4219
4262
|
var JUnitReporter = class {
|
|
4220
4263
|
constructor(options) {
|
|
4221
4264
|
this.totalTests = 0;
|
|
@@ -4225,9 +4268,11 @@ var JUnitReporter = class {
|
|
|
4225
4268
|
this.stripANSIControlSequences = false;
|
|
4226
4269
|
this.includeProjectInTestName = false;
|
|
4227
4270
|
this.includeRetries = false;
|
|
4228
|
-
this.
|
|
4229
|
-
this.
|
|
4230
|
-
this.
|
|
4271
|
+
this.omitTags = false;
|
|
4272
|
+
this.stripANSIControlSequences = getAsBooleanFromENV3("PLAYWRIGHT_JUNIT_STRIP_ANSI", !!options.stripANSIControlSequences);
|
|
4273
|
+
this.includeProjectInTestName = getAsBooleanFromENV3("PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME", !!options.includeProjectInTestName);
|
|
4274
|
+
this.includeRetries = getAsBooleanFromENV3("PLAYWRIGHT_JUNIT_INCLUDE_RETRIES", !!options.includeRetries);
|
|
4275
|
+
this.omitTags = getAsBooleanFromENV3("PLAYWRIGHT_JUNIT_OMIT_TAGS", !!options.omitTags);
|
|
4231
4276
|
this.configDir = options.configDir;
|
|
4232
4277
|
this.resolvedOutputFile = resolveOutputFile("JUNIT", options)?.outputFile;
|
|
4233
4278
|
}
|
|
@@ -4380,7 +4425,7 @@ var JUnitReporter = class {
|
|
|
4380
4425
|
entry.children.push({
|
|
4381
4426
|
name: errorInfo.elementName,
|
|
4382
4427
|
attributes: { message: errorInfo.message, type: errorInfo.type },
|
|
4383
|
-
text: (0, import_util9.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test))
|
|
4428
|
+
text: (0, import_util9.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test, void 0, { omitTags: this.omitTags }))
|
|
4384
4429
|
});
|
|
4385
4430
|
return errorInfo.elementName;
|
|
4386
4431
|
}
|
|
@@ -4390,7 +4435,7 @@ var JUnitReporter = class {
|
|
|
4390
4435
|
message: `${import_path10.default.basename(test.location.file)}:${test.location.line}:${test.location.column} ${test.title}`,
|
|
4391
4436
|
type: "FAILURE"
|
|
4392
4437
|
},
|
|
4393
|
-
text: (0, import_util9.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test))
|
|
4438
|
+
text: (0, import_util9.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test, void 0, { omitTags: this.omitTags }))
|
|
4394
4439
|
});
|
|
4395
4440
|
return "failure";
|
|
4396
4441
|
}
|
|
@@ -4501,9 +4546,10 @@ function escape(text, stripANSIControlSequences, isCharacterData) {
|
|
|
4501
4546
|
var junit_default = JUnitReporter;
|
|
4502
4547
|
|
|
4503
4548
|
// packages/playwright/src/reporters/line.ts
|
|
4549
|
+
var { getAsBooleanFromENV: getAsBooleanFromENV4 } = require("playwright-core/lib/coreBundle").utils;
|
|
4504
4550
|
var LineReporter = class extends TerminalReporter {
|
|
4505
|
-
constructor() {
|
|
4506
|
-
super(...
|
|
4551
|
+
constructor(options) {
|
|
4552
|
+
super({ ...options, omitTags: getAsBooleanFromENV4("PLAYWRIGHT_LINE_OMIT_TAGS", options?.omitTags) });
|
|
4507
4553
|
this._current = 0;
|
|
4508
4554
|
this._failures = 0;
|
|
4509
4555
|
this._didBegin = false;
|
|
@@ -4612,13 +4658,13 @@ var line_default = LineReporter;
|
|
|
4612
4658
|
// packages/playwright/src/reporters/list.ts
|
|
4613
4659
|
var import_util10 = require("../util");
|
|
4614
4660
|
var { msToString: msToString3 } = require("playwright-core/lib/coreBundle").iso;
|
|
4615
|
-
var { getAsBooleanFromENV:
|
|
4661
|
+
var { getAsBooleanFromENV: getAsBooleanFromENV5 } = require("playwright-core/lib/coreBundle").utils;
|
|
4616
4662
|
var DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === "win32" && process.env.TERM_PROGRAM !== "vscode" && !process.env.WT_SESSION;
|
|
4617
4663
|
var POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? "ok" : "\u2713";
|
|
4618
4664
|
var NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? "x" : "\u2718";
|
|
4619
4665
|
var ListReporter = class extends TerminalReporter {
|
|
4620
4666
|
constructor(options) {
|
|
4621
|
-
super(options);
|
|
4667
|
+
super({ ...options, omitTags: getAsBooleanFromENV5("PLAYWRIGHT_LIST_OMIT_TAGS", options?.omitTags) });
|
|
4622
4668
|
this._lastRow = 0;
|
|
4623
4669
|
this._lastColumn = 0;
|
|
4624
4670
|
this._testRows = /* @__PURE__ */ new Map();
|
|
@@ -4628,8 +4674,8 @@ var ListReporter = class extends TerminalReporter {
|
|
|
4628
4674
|
this._needNewLine = false;
|
|
4629
4675
|
this._failureIndex = 0;
|
|
4630
4676
|
this._paused = /* @__PURE__ */ new Set();
|
|
4631
|
-
this._printSteps =
|
|
4632
|
-
this._printFailuresInline =
|
|
4677
|
+
this._printSteps = getAsBooleanFromENV5("PLAYWRIGHT_LIST_PRINT_STEPS", options?.printSteps);
|
|
4678
|
+
this._printFailuresInline = getAsBooleanFromENV5("PLAYWRIGHT_LIST_PRINT_FAILURES_INLINE", options?.printFailuresInline);
|
|
4633
4679
|
}
|
|
4634
4680
|
onBegin(suite) {
|
|
4635
4681
|
super.onBegin(suite);
|
|
@@ -4888,29 +4934,383 @@ var ListModeReporter = class {
|
|
|
4888
4934
|
};
|
|
4889
4935
|
var listModeReporter_default = ListModeReporter;
|
|
4890
4936
|
|
|
4937
|
+
// packages/playwright/src/reporters/perfetto.ts
|
|
4938
|
+
var import_fs8 = __toESM(require("fs"));
|
|
4939
|
+
var import_path12 = __toESM(require("path"));
|
|
4940
|
+
var import_zlib = __toESM(require("zlib"));
|
|
4941
|
+
var import_coreBundle2 = require("playwright-core/lib/coreBundle");
|
|
4942
|
+
var import_util11 = require("../util");
|
|
4943
|
+
var { toPosixPath: toPosixPath4 } = require("playwright-core/lib/coreBundle").utils;
|
|
4944
|
+
var kStatusColors = {
|
|
4945
|
+
passed: "good",
|
|
4946
|
+
failed: "bad",
|
|
4947
|
+
timedOut: "terrible",
|
|
4948
|
+
interrupted: "yellow",
|
|
4949
|
+
skipped: "grey"
|
|
4950
|
+
};
|
|
4951
|
+
var kProcessId = 1;
|
|
4952
|
+
var kRunThreadId = 0;
|
|
4953
|
+
var PerfettoReporter = class {
|
|
4954
|
+
constructor(options) {
|
|
4955
|
+
this._events = [];
|
|
4956
|
+
this._laneEndTime = /* @__PURE__ */ new Map();
|
|
4957
|
+
this._globalErrors = [];
|
|
4958
|
+
this._resolvedOutputFile = resolveOutputFile("PERFETTO", {
|
|
4959
|
+
...options,
|
|
4960
|
+
default: {
|
|
4961
|
+
fileName: "perfetto.json",
|
|
4962
|
+
outputDir: "test-results"
|
|
4963
|
+
}
|
|
4964
|
+
}).outputFile;
|
|
4965
|
+
}
|
|
4966
|
+
version() {
|
|
4967
|
+
return "v2";
|
|
4968
|
+
}
|
|
4969
|
+
printsToStdio() {
|
|
4970
|
+
return false;
|
|
4971
|
+
}
|
|
4972
|
+
onConfigure(config2) {
|
|
4973
|
+
this._config = config2;
|
|
4974
|
+
}
|
|
4975
|
+
onBegin(suite) {
|
|
4976
|
+
this._suite = suite;
|
|
4977
|
+
}
|
|
4978
|
+
onError(error) {
|
|
4979
|
+
this._globalErrors.push({ error, timestamp: Date.now() });
|
|
4980
|
+
}
|
|
4981
|
+
async onEnd(result) {
|
|
4982
|
+
const entries = [];
|
|
4983
|
+
for (const test of this._suite?.allTests() ?? []) {
|
|
4984
|
+
for (const testResult of test.results)
|
|
4985
|
+
entries.push({ test, result: testResult });
|
|
4986
|
+
}
|
|
4987
|
+
entries.sort((a, b) => a.result.startTime.getTime() - b.result.startTime.getTime());
|
|
4988
|
+
for (const entry of entries)
|
|
4989
|
+
this._appendTestResult(entry.test, entry.result);
|
|
4990
|
+
for (const { error, timestamp } of this._globalErrors) {
|
|
4991
|
+
this._events.push({
|
|
4992
|
+
name: "error",
|
|
4993
|
+
cat: "error",
|
|
4994
|
+
ph: "i",
|
|
4995
|
+
s: "g",
|
|
4996
|
+
ts: timestamp,
|
|
4997
|
+
pid: kProcessId,
|
|
4998
|
+
tid: kRunThreadId,
|
|
4999
|
+
cname: "bad",
|
|
5000
|
+
args: { error: this._formatError(error) }
|
|
5001
|
+
});
|
|
5002
|
+
}
|
|
5003
|
+
await this._writeReport(result);
|
|
5004
|
+
}
|
|
5005
|
+
_appendTestResult(test, result) {
|
|
5006
|
+
const startMs = result.startTime.getTime();
|
|
5007
|
+
let endMs = startMs + Math.max(0, result.duration);
|
|
5008
|
+
for (const step of result.steps)
|
|
5009
|
+
endMs = Math.max(endMs, stepEndTime(step));
|
|
5010
|
+
const lane = this._allocateLane(result.parallelIndex, startMs);
|
|
5011
|
+
this._laneEndTime.set(lane, endMs);
|
|
5012
|
+
const tid = lane + 1;
|
|
5013
|
+
this._events.push({
|
|
5014
|
+
name: test.title,
|
|
5015
|
+
cat: "test",
|
|
5016
|
+
ph: "X",
|
|
5017
|
+
ts: startMs,
|
|
5018
|
+
dur: endMs - startMs,
|
|
5019
|
+
pid: kProcessId,
|
|
5020
|
+
tid,
|
|
5021
|
+
cname: kStatusColors[result.status],
|
|
5022
|
+
args: this._testArgs(test, result)
|
|
5023
|
+
});
|
|
5024
|
+
for (const step of result.steps)
|
|
5025
|
+
this._appendStep(step, tid, startMs, endMs);
|
|
5026
|
+
}
|
|
5027
|
+
_allocateLane(preferredLane, startMs) {
|
|
5028
|
+
const preferred = Math.max(0, preferredLane);
|
|
5029
|
+
if (!(this._laneEndTime.get(preferred) > startMs))
|
|
5030
|
+
return preferred;
|
|
5031
|
+
for (let lane = 0; ; ++lane) {
|
|
5032
|
+
if (!(this._laneEndTime.get(lane) > startMs))
|
|
5033
|
+
return lane;
|
|
5034
|
+
}
|
|
5035
|
+
}
|
|
5036
|
+
_appendStep(step, tid, parentStart, parentEnd) {
|
|
5037
|
+
const stepStart = step.startTime.getTime();
|
|
5038
|
+
const startMs = clamp(stepStart, parentStart, parentEnd);
|
|
5039
|
+
const endMs = clamp(step.duration >= 0 ? stepStart + step.duration : parentEnd, startMs, parentEnd);
|
|
5040
|
+
this._events.push({
|
|
5041
|
+
name: step.subtitle ? `${step.title} ${step.subtitle}` : step.title,
|
|
5042
|
+
cat: step.category,
|
|
5043
|
+
ph: "X",
|
|
5044
|
+
ts: startMs,
|
|
5045
|
+
dur: endMs - startMs,
|
|
5046
|
+
pid: kProcessId,
|
|
5047
|
+
tid,
|
|
5048
|
+
cname: step.error ? "bad" : void 0,
|
|
5049
|
+
args: this._stepArgs(step)
|
|
5050
|
+
});
|
|
5051
|
+
for (const child of step.steps)
|
|
5052
|
+
this._appendStep(child, tid, startMs, endMs);
|
|
5053
|
+
}
|
|
5054
|
+
_testArgs(test, result) {
|
|
5055
|
+
const [, projectName, , ...titles] = test.titlePath();
|
|
5056
|
+
const args = {
|
|
5057
|
+
status: result.status,
|
|
5058
|
+
expectedStatus: test.expectedStatus,
|
|
5059
|
+
testId: test.id,
|
|
5060
|
+
workerIndex: result.workerIndex,
|
|
5061
|
+
parallelIndex: result.parallelIndex,
|
|
5062
|
+
timeout: test.timeout,
|
|
5063
|
+
location: this._formatLocation(test.location)
|
|
5064
|
+
};
|
|
5065
|
+
if (titles.length > 1)
|
|
5066
|
+
args.title = titles.join(" \u203A ");
|
|
5067
|
+
if (projectName)
|
|
5068
|
+
args.project = projectName;
|
|
5069
|
+
if (result.retry)
|
|
5070
|
+
args.retry = result.retry;
|
|
5071
|
+
if (test.tags.length)
|
|
5072
|
+
args.tags = test.tags.join(" ");
|
|
5073
|
+
if (result.annotations.length)
|
|
5074
|
+
args.annotations = result.annotations.map((annotation) => formatAnnotation(annotation));
|
|
5075
|
+
if (result.attachments.length)
|
|
5076
|
+
args.attachments = result.attachments.map((attachment) => this._formatAttachment(attachment));
|
|
5077
|
+
if (result.errors.length)
|
|
5078
|
+
args.errors = result.errors.map((error) => this._formatError(error));
|
|
5079
|
+
const stdout = concatChunks(result.stdout);
|
|
5080
|
+
if (stdout)
|
|
5081
|
+
args.stdout = stdout;
|
|
5082
|
+
const stderr = concatChunks(result.stderr);
|
|
5083
|
+
if (stderr)
|
|
5084
|
+
args.stderr = stderr;
|
|
5085
|
+
return args;
|
|
5086
|
+
}
|
|
5087
|
+
_stepArgs(step) {
|
|
5088
|
+
const args = {};
|
|
5089
|
+
if (step.params)
|
|
5090
|
+
args.params = step.params;
|
|
5091
|
+
if (step.location)
|
|
5092
|
+
args.location = this._formatLocation(step.location);
|
|
5093
|
+
if (step.annotations.length)
|
|
5094
|
+
args.annotations = step.annotations.map((annotation) => formatAnnotation(annotation));
|
|
5095
|
+
if (step.attachments.length)
|
|
5096
|
+
args.attachments = step.attachments.map((attachment) => this._formatAttachment(attachment));
|
|
5097
|
+
if (step.error)
|
|
5098
|
+
args.error = this._formatError(step.error);
|
|
5099
|
+
return Object.keys(args).length ? args : void 0;
|
|
5100
|
+
}
|
|
5101
|
+
_formatAttachment(attachment) {
|
|
5102
|
+
return attachment.path ? this._relativePath(attachment.path) : attachment.name;
|
|
5103
|
+
}
|
|
5104
|
+
_formatLocation(location) {
|
|
5105
|
+
if (!location)
|
|
5106
|
+
return void 0;
|
|
5107
|
+
return `${this._relativePath(location.file)}:${location.line}:${location.column}`;
|
|
5108
|
+
}
|
|
5109
|
+
_formatError(error) {
|
|
5110
|
+
return (0, import_util11.stripAnsiEscapes)(formatError(nonTerminalScreen, error).message);
|
|
5111
|
+
}
|
|
5112
|
+
_relativePath(file) {
|
|
5113
|
+
return toPosixPath4(import_path12.default.relative(this._config.rootDir, file));
|
|
5114
|
+
}
|
|
5115
|
+
async _writeReport(result) {
|
|
5116
|
+
let timeOrigin2 = result.startTime.getTime();
|
|
5117
|
+
for (const event of this._events)
|
|
5118
|
+
timeOrigin2 = Math.min(timeOrigin2, event.ts);
|
|
5119
|
+
const metadataEvents = [
|
|
5120
|
+
{ name: "process_name", cat: "__metadata", ph: "M", ts: 0, pid: kProcessId, tid: kRunThreadId, args: { name: "Playwright Test" } },
|
|
5121
|
+
{ name: "process_sort_index", cat: "__metadata", ph: "M", ts: 0, pid: kProcessId, tid: kRunThreadId, args: { sort_index: 0 } }
|
|
5122
|
+
];
|
|
5123
|
+
for (const lane of [...this._laneEndTime.keys()].sort((a, b) => a - b)) {
|
|
5124
|
+
metadataEvents.push({ name: "thread_name", cat: "__metadata", ph: "M", ts: 0, pid: kProcessId, tid: lane + 1, args: { name: `Worker ${lane}` } });
|
|
5125
|
+
metadataEvents.push({ name: "thread_sort_index", cat: "__metadata", ph: "M", ts: 0, pid: kProcessId, tid: lane + 1, args: { sort_index: lane + 1 } });
|
|
5126
|
+
}
|
|
5127
|
+
this._events.sort((a, b) => a.ts - b.ts);
|
|
5128
|
+
for (const event of this._events) {
|
|
5129
|
+
event.ts = Math.round((event.ts - timeOrigin2) * 1e3);
|
|
5130
|
+
if (event.dur !== void 0)
|
|
5131
|
+
event.dur = Math.round(event.dur * 1e3);
|
|
5132
|
+
}
|
|
5133
|
+
const metadata = {
|
|
5134
|
+
"playwright-version": (0, import_coreBundle2.getPlaywrightVersion)(),
|
|
5135
|
+
"start-time": result.startTime.toISOString(),
|
|
5136
|
+
"duration": result.duration,
|
|
5137
|
+
"status": result.status
|
|
5138
|
+
};
|
|
5139
|
+
await import_fs8.default.promises.mkdir(import_path12.default.dirname(this._resolvedOutputFile), { recursive: true });
|
|
5140
|
+
const writer = new ChunkWriter(this._resolvedOutputFile);
|
|
5141
|
+
await writer.write('{"traceEvents":[');
|
|
5142
|
+
let separator2 = "";
|
|
5143
|
+
for (const events of [metadataEvents, this._events]) {
|
|
5144
|
+
for (const event of events) {
|
|
5145
|
+
await writer.write(separator2 + JSON.stringify(event));
|
|
5146
|
+
separator2 = ",";
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
await writer.write(`],"displayTimeUnit":"ms","metadata":${JSON.stringify(metadata)}}`);
|
|
5150
|
+
await writer.close();
|
|
5151
|
+
}
|
|
5152
|
+
};
|
|
5153
|
+
var ChunkWriter = class {
|
|
5154
|
+
constructor(file) {
|
|
5155
|
+
const fileStream = import_fs8.default.createWriteStream(file);
|
|
5156
|
+
const gzip = file.endsWith(".gz") ? import_zlib.default.createGzip() : void 0;
|
|
5157
|
+
gzip?.pipe(fileStream);
|
|
5158
|
+
this._stream = gzip ?? fileStream;
|
|
5159
|
+
this._closed = new Promise((resolve) => fileStream.on("close", resolve));
|
|
5160
|
+
for (const stream of /* @__PURE__ */ new Set([this._stream, fileStream]))
|
|
5161
|
+
stream.on("error", (error) => this._error ??= error);
|
|
5162
|
+
}
|
|
5163
|
+
async write(chunk) {
|
|
5164
|
+
if (this._error)
|
|
5165
|
+
throw this._error;
|
|
5166
|
+
if (!this._stream.write(chunk))
|
|
5167
|
+
await new Promise((resolve) => this._stream.once("drain", () => resolve()));
|
|
5168
|
+
}
|
|
5169
|
+
async close() {
|
|
5170
|
+
this._stream.end();
|
|
5171
|
+
await this._closed;
|
|
5172
|
+
if (this._error)
|
|
5173
|
+
throw this._error;
|
|
5174
|
+
}
|
|
5175
|
+
};
|
|
5176
|
+
function stepEndTime(step) {
|
|
5177
|
+
let end = step.startTime.getTime() + Math.max(0, step.duration);
|
|
5178
|
+
for (const child of step.steps)
|
|
5179
|
+
end = Math.max(end, stepEndTime(child));
|
|
5180
|
+
return end;
|
|
5181
|
+
}
|
|
5182
|
+
function formatAnnotation(annotation) {
|
|
5183
|
+
return annotation.description ? `${annotation.type}: ${annotation.description}` : annotation.type;
|
|
5184
|
+
}
|
|
5185
|
+
function clamp(value, min, max) {
|
|
5186
|
+
return Math.min(Math.max(value, min), max);
|
|
5187
|
+
}
|
|
5188
|
+
function concatChunks(chunks) {
|
|
5189
|
+
return chunks.map((chunk) => typeof chunk === "string" ? chunk : chunk.toString("utf8")).join("");
|
|
5190
|
+
}
|
|
5191
|
+
var perfetto_default = PerfettoReporter;
|
|
5192
|
+
|
|
4891
5193
|
// packages/playwright/src/reporters/smoothdeploy.ts
|
|
4892
|
-
var
|
|
4893
|
-
var
|
|
5194
|
+
var fs10 = __toESM(require("fs"));
|
|
5195
|
+
var path13 = __toESM(require("path"));
|
|
5196
|
+
|
|
5197
|
+
// packages/playwright/src/reporters/smoothdeployMatch.ts
|
|
5198
|
+
var ACTION_API = {
|
|
5199
|
+
navigate: ["Frame.goto"],
|
|
5200
|
+
click: ["Frame.click", "Frame.dblclick", "Frame.dispatchEvent"],
|
|
5201
|
+
fill: ["Frame.fill"],
|
|
5202
|
+
press: ["Frame.press"],
|
|
5203
|
+
hover: ["Frame.hover"],
|
|
5204
|
+
check: ["Frame.check"],
|
|
5205
|
+
uncheck: ["Frame.uncheck"],
|
|
5206
|
+
select: ["Frame.selectOption"],
|
|
5207
|
+
setInputFiles: ["Frame.setInputFiles", "ElementHandle.setInputFiles"],
|
|
5208
|
+
openPage: ["BrowserContext.newPage"],
|
|
5209
|
+
closePage: ["Page.close"],
|
|
5210
|
+
assertVisible: ["toBeVisible"],
|
|
5211
|
+
assertText: ["toContainText", "toHaveText"],
|
|
5212
|
+
assertValue: ["toHaveValue", "toBeEmpty"],
|
|
5213
|
+
assertChecked: ["toBeChecked", "not.toBeChecked"],
|
|
5214
|
+
assertSnapshot: ["toHaveScreenshot", "toMatchAriaSnapshot"]
|
|
5215
|
+
};
|
|
5216
|
+
var FILLER_API_NEVER_SKIPS_AHEAD = /* @__PURE__ */ new Set(["Frame.dispatchEvent"]);
|
|
5217
|
+
function stepApi(step) {
|
|
5218
|
+
if (step.category === "pw:api")
|
|
5219
|
+
return step.channelMethod ?? null;
|
|
5220
|
+
return normalizeApiName(step.apiName);
|
|
5221
|
+
}
|
|
5222
|
+
function shortApi(step) {
|
|
5223
|
+
const api = stepApi(step);
|
|
5224
|
+
if (!api)
|
|
5225
|
+
return null;
|
|
5226
|
+
const idx = api.lastIndexOf(".");
|
|
5227
|
+
return step.category === "pw:api" && idx >= 0 ? api.slice(idx + 1) : api;
|
|
5228
|
+
}
|
|
5229
|
+
function normalizeApiName(apiName) {
|
|
5230
|
+
if (!apiName)
|
|
5231
|
+
return null;
|
|
5232
|
+
if (apiName.startsWith("expect")) {
|
|
5233
|
+
if (apiName.includes(".poll") || apiName.includes(".soft"))
|
|
5234
|
+
return null;
|
|
5235
|
+
const matcher = apiName.slice("expect".length).replace(/^\./, "");
|
|
5236
|
+
return matcher || null;
|
|
5237
|
+
}
|
|
5238
|
+
const idx = apiName.lastIndexOf(".");
|
|
5239
|
+
return idx >= 0 ? apiName.slice(idx + 1) : apiName;
|
|
5240
|
+
}
|
|
5241
|
+
function apiMatches(step, expected) {
|
|
5242
|
+
const api = stepApi(step);
|
|
5243
|
+
if (!api)
|
|
5244
|
+
return false;
|
|
5245
|
+
const allowed = ACTION_API[expected.action];
|
|
5246
|
+
return !!allowed && allowed.includes(api);
|
|
5247
|
+
}
|
|
5248
|
+
function groupMatches(step, expected) {
|
|
5249
|
+
if (expected.title !== void 0)
|
|
5250
|
+
return step.title === expected.title;
|
|
5251
|
+
return expected.action === "group";
|
|
5252
|
+
}
|
|
5253
|
+
function stepMatches(step, expected) {
|
|
5254
|
+
if (step.category === "test.step")
|
|
5255
|
+
return groupMatches(step, expected);
|
|
5256
|
+
if (step.category === "pw:api" || step.category === "expect")
|
|
5257
|
+
return apiMatches(step, expected);
|
|
5258
|
+
return false;
|
|
5259
|
+
}
|
|
5260
|
+
function matchStep(step, siblings, cursor) {
|
|
5261
|
+
if (cursor < siblings.length && stepMatches(step, siblings[cursor]))
|
|
5262
|
+
return cursor;
|
|
5263
|
+
const api = stepApi(step);
|
|
5264
|
+
const canLookAhead = step.category === "test.step" ? siblings.some((s) => s.title !== void 0) : !!api && !FILLER_API_NEVER_SKIPS_AHEAD.has(api);
|
|
5265
|
+
if (!canLookAhead)
|
|
5266
|
+
return -1;
|
|
5267
|
+
for (let j = cursor + 1; j < siblings.length; j++) {
|
|
5268
|
+
if (stepMatches(step, siblings[j]))
|
|
5269
|
+
return j;
|
|
5270
|
+
}
|
|
5271
|
+
return -1;
|
|
5272
|
+
}
|
|
5273
|
+
var INTERNAL_STEP_TITLES = /* @__PURE__ */ new Set([
|
|
5274
|
+
"Before Hooks",
|
|
5275
|
+
"After Hooks",
|
|
5276
|
+
"Worker Cleanup",
|
|
5277
|
+
"Launch browser",
|
|
5278
|
+
"Launch persistent context",
|
|
5279
|
+
"Connect over CDP",
|
|
5280
|
+
"Close browser",
|
|
5281
|
+
"Create context",
|
|
5282
|
+
"Close context",
|
|
5283
|
+
"Create page",
|
|
5284
|
+
"Close page",
|
|
5285
|
+
"Create CDP session"
|
|
5286
|
+
]);
|
|
5287
|
+
function isToPassWrapper(step) {
|
|
5288
|
+
return normalizeApiName(step.apiName) === "toPass";
|
|
5289
|
+
}
|
|
5290
|
+
function isUserStep(step) {
|
|
5291
|
+
if (step.category === "hook" || step.category === "fixture" || step.category === "test.attach")
|
|
5292
|
+
return false;
|
|
5293
|
+
if (step.title.startsWith('Fixture "'))
|
|
5294
|
+
return false;
|
|
5295
|
+
return !INTERNAL_STEP_TITLES.has(step.title);
|
|
5296
|
+
}
|
|
5297
|
+
|
|
5298
|
+
// packages/playwright/src/reporters/smoothdeploy.ts
|
|
5299
|
+
var NO_SCREENSHOT_PREFIXES = ["Navigate", "Go back", "Go forward", "Reload", "Screenshot", "Wait for", "Pause", "Evaluate"];
|
|
5300
|
+
var safeId = (id) => id.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
4894
5301
|
var SmoothDeployReporter = class {
|
|
4895
5302
|
constructor() {
|
|
4896
5303
|
this._configDir = "";
|
|
4897
5304
|
this._manifest = null;
|
|
4898
|
-
// Resolved manifest test + paramIndex for each active pw test
|
|
4899
5305
|
this._resolvedTests = /* @__PURE__ */ new Map();
|
|
4900
|
-
|
|
4901
|
-
this.
|
|
4902
|
-
|
|
4903
|
-
this.
|
|
4904
|
-
// Accumulate nested step data per test for output manifest
|
|
5306
|
+
this._matched = /* @__PURE__ */ new WeakMap();
|
|
5307
|
+
this._opaqueFiller = /* @__PURE__ */ new WeakSet();
|
|
5308
|
+
this._retries = /* @__PURE__ */ new WeakMap();
|
|
5309
|
+
this._rootCursors = /* @__PURE__ */ new Map();
|
|
4905
5310
|
this._testSteps = /* @__PURE__ */ new Map();
|
|
4906
|
-
// Track parent step → output StepData for nesting output
|
|
4907
|
-
this._stepToOutput = /* @__PURE__ */ new WeakMap();
|
|
4908
|
-
// ID remap: pw IDs → manifest IDs (sanitized). Built during execution, applied in onEnd.
|
|
4909
5311
|
this._testIdMap = /* @__PURE__ */ new Map();
|
|
4910
|
-
// safePwTestId → safeManifestTestId
|
|
4911
5312
|
this._stepIdMap = /* @__PURE__ */ new Map();
|
|
4912
5313
|
}
|
|
4913
|
-
// safePwStepId → safeManifestStepId
|
|
4914
5314
|
version() {
|
|
4915
5315
|
return "v2";
|
|
4916
5316
|
}
|
|
@@ -4918,55 +5318,47 @@ var SmoothDeployReporter = class {
|
|
|
4918
5318
|
return false;
|
|
4919
5319
|
}
|
|
4920
5320
|
onConfigure(config2) {
|
|
4921
|
-
this._configDir = config2.configFile ?
|
|
4922
|
-
this.
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
process.stdout.write(`[SMOOTHDEPLOY_EVENT]${JSON.stringify(event)}
|
|
5321
|
+
this._configDir = config2.configFile ? path13.dirname(config2.configFile) : config2.rootDir;
|
|
5322
|
+
const manifestPath = path13.join(this._configDir, ".smoothdeploy-manifest.json");
|
|
5323
|
+
if (fs10.existsSync(manifestPath))
|
|
5324
|
+
this._manifest = JSON.parse(fs10.readFileSync(manifestPath, "utf-8"));
|
|
5325
|
+
}
|
|
5326
|
+
_emit(event, step) {
|
|
5327
|
+
const retry = step && this._nearestRetry(step);
|
|
5328
|
+
if (retry)
|
|
5329
|
+
retry.events.push(event);
|
|
5330
|
+
else
|
|
5331
|
+
process.stdout.write(`[SMOOTHDEPLOY_EVENT]${JSON.stringify(event)}
|
|
4933
5332
|
`);
|
|
4934
5333
|
}
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
"Launch browser",
|
|
4943
|
-
"Launch persistent context",
|
|
4944
|
-
"Connect over CDP",
|
|
4945
|
-
"Close browser",
|
|
4946
|
-
"Create context",
|
|
4947
|
-
"Close context",
|
|
4948
|
-
"Create page",
|
|
4949
|
-
"Close page",
|
|
4950
|
-
"Create CDP session"
|
|
4951
|
-
];
|
|
4952
|
-
if (internalSteps.includes(title))
|
|
4953
|
-
return false;
|
|
4954
|
-
return true;
|
|
5334
|
+
_nearestRetry(step) {
|
|
5335
|
+
for (let p = step.parent; p; p = p.parent) {
|
|
5336
|
+
const retry = this._retries.get(p);
|
|
5337
|
+
if (retry)
|
|
5338
|
+
return retry;
|
|
5339
|
+
}
|
|
5340
|
+
return void 0;
|
|
4955
5341
|
}
|
|
4956
|
-
// Resolve a pw TestCase to its manifest test entry + param index.
|
|
4957
|
-
// For parameterized tests: manifest title "Foo" with params=3 matches pw titles "Foo0", "Foo1", "Foo2".
|
|
4958
|
-
// For non-parameterized tests: exact match, paramIndex=0.
|
|
4959
5342
|
_resolveManifestTest(test) {
|
|
5343
|
+
const projectName = test.parent.project()?.name ?? "";
|
|
5344
|
+
const manifestTest = this._findManifestTest(test);
|
|
5345
|
+
if (!manifestTest)
|
|
5346
|
+
return { manifestTest: { id: test.id, title: test.title, steps: [] }, projectName, passthrough: true };
|
|
5347
|
+
const single = manifestTest.steps.length === 1 ? manifestTest.steps[0] : void 0;
|
|
5348
|
+
if (single && single.action === "script")
|
|
5349
|
+
return { manifestTest, projectName, passthrough: true, passthroughRootId: single.id };
|
|
5350
|
+
return { manifestTest, projectName, passthrough: false };
|
|
5351
|
+
}
|
|
5352
|
+
_findManifestTest(test) {
|
|
4960
5353
|
if (!this._manifest)
|
|
4961
5354
|
return null;
|
|
4962
5355
|
const titlePath = test.titlePath();
|
|
4963
|
-
const relFile =
|
|
5356
|
+
const relFile = path13.relative(this._configDir, test.location.file);
|
|
4964
5357
|
const fileManifest = this._manifest.files[relFile];
|
|
4965
5358
|
if (!fileManifest)
|
|
4966
5359
|
return null;
|
|
4967
5360
|
const fileIdx = titlePath.indexOf(relFile);
|
|
4968
5361
|
const describeTitles = fileIdx >= 0 ? titlePath.slice(fileIdx + 1, -1) : [];
|
|
4969
|
-
const testTitle = test.title;
|
|
4970
5362
|
let currentSuites = fileManifest.suites;
|
|
4971
5363
|
let currentTests = fileManifest.tests;
|
|
4972
5364
|
for (const desc of describeTitles) {
|
|
@@ -4976,75 +5368,131 @@ var SmoothDeployReporter = class {
|
|
|
4976
5368
|
currentSuites = suite.suites;
|
|
4977
5369
|
currentTests = suite.tests;
|
|
4978
5370
|
}
|
|
4979
|
-
|
|
4980
|
-
if (exactMatch)
|
|
4981
|
-
return { manifestTest: exactMatch, paramIndex: 0 };
|
|
4982
|
-
for (const mt of currentTests) {
|
|
4983
|
-
if (!mt.params || mt.params < 1)
|
|
4984
|
-
continue;
|
|
4985
|
-
if (!testTitle.startsWith(mt.title))
|
|
4986
|
-
continue;
|
|
4987
|
-
const suffix = testTitle.slice(mt.title.length);
|
|
4988
|
-
const idx = parseInt(suffix, 10);
|
|
4989
|
-
if (String(idx) === suffix && idx >= 0 && idx < mt.params)
|
|
4990
|
-
return { manifestTest: mt, paramIndex: idx };
|
|
4991
|
-
}
|
|
4992
|
-
return null;
|
|
5371
|
+
return currentTests.find((t2) => t2.title === test.title) ?? null;
|
|
4993
5372
|
}
|
|
4994
5373
|
onTestBegin(test, result) {
|
|
4995
5374
|
const resolved = this._resolveManifestTest(test);
|
|
4996
|
-
if (!resolved)
|
|
4997
|
-
return;
|
|
4998
5375
|
this._resolvedTests.set(test.id, resolved);
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
this._testIdMap.set(safePw, safeManifest);
|
|
5002
|
-
this._childCounters.set(test.id, 0);
|
|
5376
|
+
this._testIdMap.set(safeId(test.id), safeId(resolved.manifestTest.id));
|
|
5377
|
+
this._rootCursors.set(test.id, 0);
|
|
5003
5378
|
this._testSteps.set(test.id, []);
|
|
5004
5379
|
this._emit({
|
|
5005
5380
|
event: "testBegin",
|
|
5006
5381
|
testId: resolved.manifestTest.id,
|
|
5007
|
-
|
|
5382
|
+
projectName: resolved.projectName,
|
|
5008
5383
|
testTitle: test.title,
|
|
5009
5384
|
timestamp: Date.now()
|
|
5010
5385
|
});
|
|
5386
|
+
if (resolved.passthroughRootId) {
|
|
5387
|
+
this._emit({
|
|
5388
|
+
event: "stepBegin",
|
|
5389
|
+
testId: resolved.manifestTest.id,
|
|
5390
|
+
projectName: resolved.projectName,
|
|
5391
|
+
id: resolved.passthroughRootId,
|
|
5392
|
+
action: "script",
|
|
5393
|
+
title: test.title,
|
|
5394
|
+
category: "test.step",
|
|
5395
|
+
timestamp: Date.now()
|
|
5396
|
+
});
|
|
5397
|
+
}
|
|
5011
5398
|
}
|
|
5012
5399
|
onTestEnd(test, result) {
|
|
5013
5400
|
const resolved = this._resolvedTests.get(test.id);
|
|
5014
5401
|
if (!resolved)
|
|
5015
5402
|
return;
|
|
5403
|
+
if (resolved.passthroughRootId) {
|
|
5404
|
+
this._emit({
|
|
5405
|
+
event: "stepEnd",
|
|
5406
|
+
testId: resolved.manifestTest.id,
|
|
5407
|
+
projectName: resolved.projectName,
|
|
5408
|
+
id: resolved.passthroughRootId,
|
|
5409
|
+
action: "script",
|
|
5410
|
+
title: test.title,
|
|
5411
|
+
duration: result.duration,
|
|
5412
|
+
error: result.error ? { message: result.error.message } : null,
|
|
5413
|
+
timestamp: Date.now()
|
|
5414
|
+
});
|
|
5415
|
+
}
|
|
5016
5416
|
this._emit({
|
|
5017
5417
|
event: "testEnd",
|
|
5018
5418
|
testId: resolved.manifestTest.id,
|
|
5019
|
-
|
|
5419
|
+
projectName: resolved.projectName,
|
|
5020
5420
|
testTitle: test.title,
|
|
5021
5421
|
status: result.status,
|
|
5022
5422
|
duration: result.duration,
|
|
5023
5423
|
timestamp: Date.now()
|
|
5024
5424
|
});
|
|
5025
|
-
this.
|
|
5425
|
+
this._rootCursors.delete(test.id);
|
|
5426
|
+
}
|
|
5427
|
+
_nearestMatchedAncestor(step) {
|
|
5428
|
+
for (let p = step.parent; p; p = p.parent) {
|
|
5429
|
+
const matched = this._matched.get(p);
|
|
5430
|
+
if (matched)
|
|
5431
|
+
return { matched, blocked: false };
|
|
5432
|
+
if (this._opaqueFiller.has(p))
|
|
5433
|
+
return { blocked: true };
|
|
5434
|
+
}
|
|
5435
|
+
return { blocked: false };
|
|
5436
|
+
}
|
|
5437
|
+
_resolveStep(test, resolved, step, parent) {
|
|
5438
|
+
const stepLike = { title: step.title, category: step.category, apiName: step._apiName, channelMethod: step._channelMethod };
|
|
5439
|
+
if (resolved.passthrough) {
|
|
5440
|
+
const index2 = parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0;
|
|
5441
|
+
const prefix = parent ? `${parent.manifest.id}:` : resolved.passthroughRootId ? `${resolved.passthroughRootId}:` : "";
|
|
5442
|
+
if (parent)
|
|
5443
|
+
parent.cursor = index2 + 1;
|
|
5444
|
+
else
|
|
5445
|
+
this._rootCursors.set(test.id, index2 + 1);
|
|
5446
|
+
const action = step.category === "test.step" ? "group" : shortApi(stepLike) ?? step.category;
|
|
5447
|
+
return { id: `${prefix}${index2}`, action, title: step.title, children: [] };
|
|
5448
|
+
}
|
|
5449
|
+
if (parent && parent.manifest.children.length === 0)
|
|
5450
|
+
return null;
|
|
5451
|
+
const siblings = parent ? parent.manifest.children : resolved.manifestTest.steps;
|
|
5452
|
+
const cursor = parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0;
|
|
5453
|
+
let index = matchStep(stepLike, siblings, cursor);
|
|
5454
|
+
const retry = this._nearestRetry(step);
|
|
5455
|
+
if (index < 0 && retry && retry.parent === parent && cursor > retry.startCursor) {
|
|
5456
|
+
index = matchStep(stepLike, siblings.slice(0, cursor), retry.startCursor);
|
|
5457
|
+
if (index >= 0)
|
|
5458
|
+
this._discardAttempt(test, retry);
|
|
5459
|
+
}
|
|
5460
|
+
if (index < 0)
|
|
5461
|
+
return null;
|
|
5462
|
+
if (parent)
|
|
5463
|
+
parent.cursor = index + 1;
|
|
5464
|
+
else
|
|
5465
|
+
this._rootCursors.set(test.id, index + 1);
|
|
5466
|
+
return siblings[index];
|
|
5467
|
+
}
|
|
5468
|
+
_discardAttempt(test, retry) {
|
|
5469
|
+
const list = retry.parent ? retry.parent.output.children : this._testSteps.get(test.id);
|
|
5470
|
+
for (const output of retry.outputs) {
|
|
5471
|
+
const i = list ? list.indexOf(output) : -1;
|
|
5472
|
+
if (i >= 0)
|
|
5473
|
+
list.splice(i, 1);
|
|
5474
|
+
}
|
|
5475
|
+
retry.outputs = [];
|
|
5476
|
+
retry.events = [];
|
|
5026
5477
|
}
|
|
5027
5478
|
onStepBegin(test, result, step) {
|
|
5028
|
-
if (!
|
|
5479
|
+
if (!isUserStep(step))
|
|
5029
5480
|
return;
|
|
5030
5481
|
const resolved = this._resolvedTests.get(test.id);
|
|
5031
5482
|
if (!resolved)
|
|
5032
5483
|
return;
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
const outputStep = {
|
|
5046
|
-
id: manifestStep?.id,
|
|
5047
|
-
action: manifestStep?.action,
|
|
5484
|
+
const { matched: parent, blocked } = this._nearestMatchedAncestor(step);
|
|
5485
|
+
const manifestStep = blocked ? null : this._resolveStep(test, resolved, step, parent);
|
|
5486
|
+
if (!manifestStep) {
|
|
5487
|
+
if (blocked || !isToPassWrapper({ title: step.title, category: step.category, apiName: step._apiName }))
|
|
5488
|
+
this._opaqueFiller.add(step);
|
|
5489
|
+
else
|
|
5490
|
+
this._retries.set(step, { parent, startCursor: parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0, events: [], outputs: [] });
|
|
5491
|
+
return;
|
|
5492
|
+
}
|
|
5493
|
+
const output = {
|
|
5494
|
+
id: manifestStep.id,
|
|
5495
|
+
action: manifestStep.action,
|
|
5048
5496
|
title: step.title,
|
|
5049
5497
|
category: step.category,
|
|
5050
5498
|
duration: 0,
|
|
@@ -5052,97 +5500,106 @@ var SmoothDeployReporter = class {
|
|
|
5052
5500
|
screenshots: null,
|
|
5053
5501
|
children: []
|
|
5054
5502
|
};
|
|
5055
|
-
this.
|
|
5056
|
-
const
|
|
5057
|
-
if (
|
|
5058
|
-
|
|
5503
|
+
this._matched.set(step, { manifest: manifestStep, output, cursor: 0 });
|
|
5504
|
+
const retry = this._nearestRetry(step);
|
|
5505
|
+
if (retry && retry.parent === parent)
|
|
5506
|
+
retry.outputs.push(output);
|
|
5507
|
+
if (parent)
|
|
5508
|
+
parent.output.children.push(output);
|
|
5059
5509
|
else
|
|
5060
|
-
this._testSteps.get(test.id)?.push(
|
|
5510
|
+
this._testSteps.get(test.id)?.push(output);
|
|
5061
5511
|
this._emit({
|
|
5062
5512
|
event: "stepBegin",
|
|
5063
5513
|
testId: resolved.manifestTest.id,
|
|
5064
|
-
|
|
5065
|
-
id: manifestStep
|
|
5066
|
-
action: manifestStep
|
|
5514
|
+
projectName: resolved.projectName,
|
|
5515
|
+
id: manifestStep.id,
|
|
5516
|
+
action: manifestStep.action,
|
|
5067
5517
|
title: step.title,
|
|
5068
5518
|
category: step.category,
|
|
5069
5519
|
timestamp: Date.now()
|
|
5070
|
-
});
|
|
5520
|
+
}, step);
|
|
5521
|
+
}
|
|
5522
|
+
_screenshotsFor(test, step) {
|
|
5523
|
+
const hasScreenshot = step.category === "pw:api" && !NO_SCREENSHOT_PREFIXES.some((prefix) => step.title.startsWith(prefix));
|
|
5524
|
+
if (!hasScreenshot)
|
|
5525
|
+
return null;
|
|
5526
|
+
const safeStepId = safeId(step._stepId ?? step.title);
|
|
5527
|
+
return {
|
|
5528
|
+
safeStepId,
|
|
5529
|
+
paths: {
|
|
5530
|
+
page: `.smoothdeploy-output/screenshots/${safeId(test.id)}/${safeStepId}-page.png`,
|
|
5531
|
+
element: `.smoothdeploy-output/screenshots/${safeId(test.id)}/${safeStepId}-element.png`
|
|
5532
|
+
}
|
|
5533
|
+
};
|
|
5071
5534
|
}
|
|
5072
5535
|
onStepEnd(test, result, step) {
|
|
5073
|
-
if (!
|
|
5536
|
+
if (!isUserStep(step))
|
|
5074
5537
|
return;
|
|
5075
5538
|
const resolved = this._resolvedTests.get(test.id);
|
|
5076
5539
|
if (!resolved)
|
|
5077
5540
|
return;
|
|
5078
|
-
const
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
outputStep.error = step.error && !hasDescendantError(outputStep.children) ? { message: step.error.message ?? "" } : null;
|
|
5106
|
-
outputStep.screenshots = screenshots;
|
|
5107
|
-
}
|
|
5108
|
-
this._childCounters.delete(step);
|
|
5541
|
+
const retry = this._retries.get(step);
|
|
5542
|
+
if (retry) {
|
|
5543
|
+
this._retries.delete(step);
|
|
5544
|
+
for (const event of retry.events)
|
|
5545
|
+
this._emit(event, step);
|
|
5546
|
+
return;
|
|
5547
|
+
}
|
|
5548
|
+
const matched = this._matched.get(step);
|
|
5549
|
+
const screenshots = this._screenshotsFor(test, step);
|
|
5550
|
+
if (!matched) {
|
|
5551
|
+
const leaf = this._nearestMatchedAncestor(step).matched;
|
|
5552
|
+
if (screenshots && leaf && leaf.manifest.children.length === 0 && !leaf.output.screenshots) {
|
|
5553
|
+
this._stepIdMap.set(screenshots.safeStepId, safeId(leaf.manifest.id));
|
|
5554
|
+
leaf.output.screenshots = screenshots.paths;
|
|
5555
|
+
}
|
|
5556
|
+
return;
|
|
5557
|
+
}
|
|
5558
|
+
if (screenshots) {
|
|
5559
|
+
this._stepIdMap.set(screenshots.safeStepId, safeId(matched.manifest.id));
|
|
5560
|
+
matched.output.screenshots = screenshots.paths;
|
|
5561
|
+
}
|
|
5562
|
+
matched.output.duration = step.duration;
|
|
5563
|
+
const skipped = step.annotations.some((a) => a.type === "skip");
|
|
5564
|
+
if (skipped)
|
|
5565
|
+
matched.output.skipped = true;
|
|
5566
|
+
const hasDescendantError = (steps) => steps.some((c) => c.error !== null || hasDescendantError(c.children));
|
|
5567
|
+
matched.output.error = step.error && !hasDescendantError(matched.output.children) ? { message: step.error.message ?? "" } : null;
|
|
5109
5568
|
this._emit({
|
|
5110
5569
|
event: "stepEnd",
|
|
5111
5570
|
testId: resolved.manifestTest.id,
|
|
5112
|
-
|
|
5113
|
-
id:
|
|
5114
|
-
action:
|
|
5571
|
+
projectName: resolved.projectName,
|
|
5572
|
+
id: matched.manifest.id,
|
|
5573
|
+
action: matched.manifest.action,
|
|
5115
5574
|
title: step.title,
|
|
5116
5575
|
duration: step.duration,
|
|
5117
5576
|
error: step.error ? { message: step.error.message } : null,
|
|
5577
|
+
skipped,
|
|
5118
5578
|
timestamp: Date.now()
|
|
5119
|
-
});
|
|
5579
|
+
}, step);
|
|
5120
5580
|
}
|
|
5121
5581
|
onEnd(result) {
|
|
5122
|
-
const outputDir =
|
|
5123
|
-
const screenshotsDir =
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
for (const [
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
if (fs9.existsSync(src))
|
|
5134
|
-
fs9.renameSync(src, dst);
|
|
5135
|
-
}
|
|
5582
|
+
const outputDir = path13.join(process.cwd(), ".smoothdeploy-output");
|
|
5583
|
+
const screenshotsDir = path13.join(outputDir, "screenshots");
|
|
5584
|
+
for (const [safePwTestId] of this._testIdMap) {
|
|
5585
|
+
const testDir = path13.join(screenshotsDir, safePwTestId);
|
|
5586
|
+
if (!fs10.existsSync(testDir))
|
|
5587
|
+
continue;
|
|
5588
|
+
for (const [safePwStepId, safeManifestStepId] of this._stepIdMap) {
|
|
5589
|
+
for (const suffix of ["-page.png", "-element.png"]) {
|
|
5590
|
+
const src = path13.join(testDir, `${safePwStepId}${suffix}`);
|
|
5591
|
+
if (fs10.existsSync(src))
|
|
5592
|
+
fs10.renameSync(src, path13.join(testDir, `${safeManifestStepId}${suffix}`));
|
|
5136
5593
|
}
|
|
5137
5594
|
}
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5595
|
+
}
|
|
5596
|
+
for (const [safePwTestId, safeManifestTestId] of this._testIdMap) {
|
|
5597
|
+
const src = path13.join(screenshotsDir, safePwTestId);
|
|
5598
|
+
const dst = path13.join(screenshotsDir, safeManifestTestId);
|
|
5599
|
+
if (src !== dst && fs10.existsSync(src)) {
|
|
5600
|
+
if (fs10.existsSync(dst))
|
|
5601
|
+
fs10.rmSync(dst, { recursive: true });
|
|
5602
|
+
fs10.renameSync(src, dst);
|
|
5146
5603
|
}
|
|
5147
5604
|
}
|
|
5148
5605
|
const remapScreenshotPaths = (steps) => {
|
|
@@ -5160,24 +5617,17 @@ var SmoothDeployReporter = class {
|
|
|
5160
5617
|
if (!resolved)
|
|
5161
5618
|
continue;
|
|
5162
5619
|
remapScreenshotPaths(steps);
|
|
5163
|
-
const safeManifestTestId = resolved.manifestTest.id
|
|
5164
|
-
const failurePath =
|
|
5165
|
-
const failureScreenshot =
|
|
5620
|
+
const safeManifestTestId = safeId(resolved.manifestTest.id);
|
|
5621
|
+
const failurePath = path13.join(screenshotsDir, safeManifestTestId, "failure.png");
|
|
5622
|
+
const failureScreenshot = fs10.existsSync(failurePath) ? `.smoothdeploy-output/screenshots/${safeManifestTestId}/failure.png` : null;
|
|
5166
5623
|
const key = resolved.manifestTest.id;
|
|
5167
5624
|
if (!manifest[key])
|
|
5168
5625
|
manifest[key] = [];
|
|
5169
|
-
manifest[key].push({
|
|
5626
|
+
manifest[key].push({ projectName: resolved.projectName, steps, failureScreenshot });
|
|
5170
5627
|
}
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
JSON.stringify(manifest, null, 2)
|
|
5175
|
-
);
|
|
5176
|
-
this._emit({
|
|
5177
|
-
event: "runEnd",
|
|
5178
|
-
status: result.status,
|
|
5179
|
-
timestamp: Date.now()
|
|
5180
|
-
});
|
|
5628
|
+
fs10.mkdirSync(outputDir, { recursive: true });
|
|
5629
|
+
fs10.writeFileSync(path13.join(outputDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
5630
|
+
this._emit({ event: "runEnd", status: result.status, timestamp: Date.now() });
|
|
5181
5631
|
}
|
|
5182
5632
|
_remapPath(screenshotPath) {
|
|
5183
5633
|
let result = screenshotPath;
|
|
@@ -5194,21 +5644,20 @@ var smoothdeploy_default = SmoothDeployReporter;
|
|
|
5194
5644
|
var { calculateSha1: calculateSha13 } = require("playwright-core/lib/coreBundle").utils;
|
|
5195
5645
|
async function createReporters(config2, mode, descriptions, runOptions) {
|
|
5196
5646
|
const defaultReporters = {
|
|
5197
|
-
blob: BlobReporter,
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5647
|
+
"blob": BlobReporter,
|
|
5648
|
+
"perfetto": perfetto_default,
|
|
5649
|
+
"dot": mode === "list" ? listModeReporter_default : dot_default,
|
|
5650
|
+
"line": mode === "list" ? listModeReporter_default : line_default,
|
|
5651
|
+
"list": mode === "list" ? listModeReporter_default : list_default,
|
|
5652
|
+
"github": github_default,
|
|
5653
|
+
"json": json_default,
|
|
5654
|
+
"junit": junit_default,
|
|
5655
|
+
"null": empty_default,
|
|
5656
|
+
"html": html_default,
|
|
5657
|
+
"smoothdeploy": smoothdeploy_default
|
|
5207
5658
|
};
|
|
5208
5659
|
const reporters = [];
|
|
5209
5660
|
descriptions ??= config2.config.reporter;
|
|
5210
|
-
if (runOptions?.additionalReporters)
|
|
5211
|
-
descriptions = [...descriptions, ...runOptions.additionalReporters];
|
|
5212
5661
|
const reportOptions = reporterCommandOptions(config2, mode, runOptions);
|
|
5213
5662
|
for (const r of descriptions) {
|
|
5214
5663
|
const [name, arg] = r;
|
|
@@ -5272,22 +5721,22 @@ function computeCommandHash(config2, runOptions) {
|
|
|
5272
5721
|
if (config2.config.tags.length)
|
|
5273
5722
|
command.tags = config2.config.tags.join(" ");
|
|
5274
5723
|
if (runOptions?.testList)
|
|
5275
|
-
command.testList = calculateSha13(
|
|
5724
|
+
command.testList = calculateSha13(import_fs9.default.readFileSync(runOptions.testList));
|
|
5276
5725
|
if (runOptions?.testListInvert)
|
|
5277
|
-
command.testListInvert = calculateSha13(
|
|
5726
|
+
command.testListInvert = calculateSha13(import_fs9.default.readFileSync(runOptions.testListInvert));
|
|
5278
5727
|
if (Object.keys(command).length)
|
|
5279
5728
|
parts.push(calculateSha13(JSON.stringify(command)).substring(0, 7));
|
|
5280
5729
|
return parts.join("-");
|
|
5281
5730
|
}
|
|
5282
5731
|
|
|
5283
5732
|
// packages/playwright/src/runner/tasks.ts
|
|
5284
|
-
var
|
|
5285
|
-
var
|
|
5286
|
-
var
|
|
5733
|
+
var import_fs12 = __toESM(require("fs"));
|
|
5734
|
+
var import_path16 = __toESM(require("path"));
|
|
5735
|
+
var import_util14 = require("util");
|
|
5287
5736
|
|
|
5288
5737
|
// packages/playwright/src/runner/rebase.ts
|
|
5289
|
-
var
|
|
5290
|
-
var
|
|
5738
|
+
var import_fs10 = __toESM(require("fs"));
|
|
5739
|
+
var import_path13 = __toESM(require("path"));
|
|
5291
5740
|
var babel3 = __toESM(require("../transform/babelBundle"));
|
|
5292
5741
|
var colors3 = require("playwright-core/lib/utilsBundle").colors;
|
|
5293
5742
|
var diff = require("playwright-core/lib/utilsBundle").diff;
|
|
@@ -5311,9 +5760,9 @@ async function applySuggestedRebaselines(config2, reporter, filteredProjects) {
|
|
|
5311
5760
|
const patches = [];
|
|
5312
5761
|
const files = [];
|
|
5313
5762
|
const gitCache = /* @__PURE__ */ new Map();
|
|
5314
|
-
const patchFile =
|
|
5763
|
+
const patchFile = import_path13.default.join(project.project.outputDir, "rebaselines.patch");
|
|
5315
5764
|
for (const fileName of [...suggestedRebaselines.keys()].sort()) {
|
|
5316
|
-
const source = await
|
|
5765
|
+
const source = await import_fs10.default.promises.readFile(fileName, "utf8");
|
|
5317
5766
|
const lines = source.split("\n");
|
|
5318
5767
|
const replacements = suggestedRebaselines.get(fileName);
|
|
5319
5768
|
const fileNode = babel3.babelParse(source, fileName, true);
|
|
@@ -5347,15 +5796,15 @@ async function applySuggestedRebaselines(config2, reporter, filteredProjects) {
|
|
|
5347
5796
|
let result = source;
|
|
5348
5797
|
for (const range of ranges)
|
|
5349
5798
|
result = result.substring(0, range.start) + range.newText + result.substring(range.end);
|
|
5350
|
-
const relativeName =
|
|
5799
|
+
const relativeName = import_path13.default.relative(process.cwd(), fileName);
|
|
5351
5800
|
files.push(relativeName);
|
|
5352
5801
|
if (config2.config.updateSourceMethod === "overwrite") {
|
|
5353
|
-
await
|
|
5802
|
+
await import_fs10.default.promises.writeFile(fileName, result);
|
|
5354
5803
|
} else if (config2.config.updateSourceMethod === "3way") {
|
|
5355
|
-
await
|
|
5804
|
+
await import_fs10.default.promises.writeFile(fileName, applyPatchWithConflictMarkers(source, result));
|
|
5356
5805
|
} else {
|
|
5357
|
-
const gitFolder = findGitRoot(
|
|
5358
|
-
const relativeToGit =
|
|
5806
|
+
const gitFolder = findGitRoot(import_path13.default.dirname(fileName), gitCache);
|
|
5807
|
+
const relativeToGit = import_path13.default.relative(gitFolder || process.cwd(), fileName);
|
|
5359
5808
|
patches.push(createPatch(relativeToGit, source, result));
|
|
5360
5809
|
}
|
|
5361
5810
|
}
|
|
@@ -5366,10 +5815,10 @@ New baselines created for:
|
|
|
5366
5815
|
${fileList}
|
|
5367
5816
|
`);
|
|
5368
5817
|
if (config2.config.updateSourceMethod === "patch") {
|
|
5369
|
-
await
|
|
5370
|
-
await
|
|
5818
|
+
await import_fs10.default.promises.mkdir(import_path13.default.dirname(patchFile), { recursive: true });
|
|
5819
|
+
await import_fs10.default.promises.writeFile(patchFile, patches.join("\n"));
|
|
5371
5820
|
reporter.onStdErr(`
|
|
5372
|
-
` + colors3.cyan("git apply " +
|
|
5821
|
+
` + colors3.cyan("git apply " + import_path13.default.relative(process.cwd(), patchFile)) + "\n");
|
|
5373
5822
|
}
|
|
5374
5823
|
}
|
|
5375
5824
|
function createPatch(fileName, before, after) {
|
|
@@ -5386,12 +5835,12 @@ function findGitRoot(dir, cache) {
|
|
|
5386
5835
|
const result = cache.get(dir);
|
|
5387
5836
|
if (result !== void 0)
|
|
5388
5837
|
return result;
|
|
5389
|
-
const gitPath =
|
|
5390
|
-
if (
|
|
5838
|
+
const gitPath = import_path13.default.join(dir, ".git");
|
|
5839
|
+
if (import_fs10.default.existsSync(gitPath) && import_fs10.default.lstatSync(gitPath).isDirectory()) {
|
|
5391
5840
|
cache.set(dir, dir);
|
|
5392
5841
|
return dir;
|
|
5393
5842
|
}
|
|
5394
|
-
const parentDir =
|
|
5843
|
+
const parentDir = import_path13.default.dirname(dir);
|
|
5395
5844
|
if (dir === parentDir) {
|
|
5396
5845
|
cache.set(dir, null);
|
|
5397
5846
|
return null;
|
|
@@ -5435,8 +5884,8 @@ function applyPatchWithConflictMarkers(oldText, newText) {
|
|
|
5435
5884
|
}
|
|
5436
5885
|
|
|
5437
5886
|
// packages/playwright/src/runner/workerHost.ts
|
|
5438
|
-
var
|
|
5439
|
-
var
|
|
5887
|
+
var import_fs11 = __toESM(require("fs"));
|
|
5888
|
+
var import_path14 = __toESM(require("path"));
|
|
5440
5889
|
var import_common6 = require("../common");
|
|
5441
5890
|
|
|
5442
5891
|
// packages/playwright/src/isomorphic/folders.ts
|
|
@@ -5465,13 +5914,13 @@ var WorkerHost = class extends ProcessHost {
|
|
|
5465
5914
|
repeatEachIndex: testGroup.repeatEachIndex,
|
|
5466
5915
|
projectId: testGroup.projectId,
|
|
5467
5916
|
config: options.config,
|
|
5468
|
-
artifactsDir:
|
|
5917
|
+
artifactsDir: import_path14.default.join(options.outputDir, artifactsFolderName(workerIndex)),
|
|
5469
5918
|
pauseOnError: options.pauseOnError,
|
|
5470
5919
|
pauseAtEnd: options.pauseAtEnd
|
|
5471
5920
|
};
|
|
5472
5921
|
}
|
|
5473
5922
|
async start() {
|
|
5474
|
-
await
|
|
5923
|
+
await import_fs11.default.promises.mkdir(this._params.artifactsDir, { recursive: true });
|
|
5475
5924
|
return await this.startRunner(this._params, {
|
|
5476
5925
|
onStdOut: (chunk) => this.emit("stdOut", import_common6.ipc.stdioChunkToParams(chunk)),
|
|
5477
5926
|
onStdErr: (chunk) => this.emit("stdErr", import_common6.ipc.stdioChunkToParams(chunk))
|
|
@@ -5507,7 +5956,7 @@ var WorkerHost = class extends ProcessHost {
|
|
|
5507
5956
|
|
|
5508
5957
|
// packages/playwright/src/runner/dispatcher.ts
|
|
5509
5958
|
var import_common7 = require("../common");
|
|
5510
|
-
var
|
|
5959
|
+
var import_util12 = require("../util");
|
|
5511
5960
|
var colors4 = require("playwright-core/lib/utilsBundle").colors;
|
|
5512
5961
|
var { ManualPromise: ManualPromise3 } = require("playwright-core/lib/coreBundle").iso;
|
|
5513
5962
|
var { eventsHelper } = require("playwright-core/lib/coreBundle").utils;
|
|
@@ -5530,11 +5979,22 @@ var Dispatcher = class {
|
|
|
5530
5979
|
this._workerLimitPerProjectId.set(project.id, project.workers);
|
|
5531
5980
|
}
|
|
5532
5981
|
}
|
|
5982
|
+
_heldLocks() {
|
|
5983
|
+
const heldLocks = /* @__PURE__ */ new Set();
|
|
5984
|
+
for (const slot of this._workerSlots) {
|
|
5985
|
+
for (const lock of slot.jobDispatcher?.job.locks || [])
|
|
5986
|
+
heldLocks.add(lock);
|
|
5987
|
+
}
|
|
5988
|
+
return heldLocks;
|
|
5989
|
+
}
|
|
5533
5990
|
_findFirstJobToRun() {
|
|
5991
|
+
const heldLocks = this._heldLocks();
|
|
5534
5992
|
for (let index = 0; index < this._queue.length; index++) {
|
|
5535
5993
|
const job = this._queue[index];
|
|
5536
5994
|
if (this._isolatedJobs.has(job) && this._workerSlots.some((w) => !!w.jobDispatcher))
|
|
5537
5995
|
continue;
|
|
5996
|
+
if (job.locks.some((lock) => heldLocks.has(lock)))
|
|
5997
|
+
continue;
|
|
5538
5998
|
const projectIdWorkerLimit = this._workerLimitPerProjectId.get(job.projectId);
|
|
5539
5999
|
if (!projectIdWorkerLimit)
|
|
5540
6000
|
return index;
|
|
@@ -5544,18 +6004,22 @@ var Dispatcher = class {
|
|
|
5544
6004
|
}
|
|
5545
6005
|
return -1;
|
|
5546
6006
|
}
|
|
6007
|
+
_scheduleJobs() {
|
|
6008
|
+
while (this._scheduleJob()) {
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
5547
6011
|
_scheduleJob() {
|
|
5548
|
-
if (this._isStopped)
|
|
5549
|
-
return;
|
|
6012
|
+
if (this._isStopped || !this._workerSlots.some((w) => !w.jobDispatcher))
|
|
6013
|
+
return false;
|
|
5550
6014
|
const jobIndex = this._findFirstJobToRun();
|
|
5551
6015
|
if (jobIndex === -1)
|
|
5552
|
-
return;
|
|
6016
|
+
return false;
|
|
5553
6017
|
const job = this._queue[jobIndex];
|
|
5554
6018
|
let workerIndex = this._workerSlots.findIndex((w) => !w.jobDispatcher && w.worker && w.worker.hash() === job.workerHash && !w.worker.didSendStop());
|
|
5555
6019
|
if (workerIndex === -1)
|
|
5556
6020
|
workerIndex = this._workerSlots.findIndex((w) => !w.jobDispatcher);
|
|
5557
6021
|
if (workerIndex === -1) {
|
|
5558
|
-
return;
|
|
6022
|
+
return false;
|
|
5559
6023
|
}
|
|
5560
6024
|
this._queue.splice(jobIndex, 1);
|
|
5561
6025
|
const jobDispatcher = new JobDispatcher(job, this._testRun, this._ignoreMaxFailures ? void 0 : () => this.stop().catch(() => {
|
|
@@ -5564,8 +6028,9 @@ var Dispatcher = class {
|
|
|
5564
6028
|
void this._runJobInWorker(workerIndex, jobDispatcher).then(() => {
|
|
5565
6029
|
this._workerSlots[workerIndex].jobDispatcher = void 0;
|
|
5566
6030
|
this._checkFinished();
|
|
5567
|
-
this.
|
|
6031
|
+
this._scheduleJobs();
|
|
5568
6032
|
});
|
|
6033
|
+
return true;
|
|
5569
6034
|
}
|
|
5570
6035
|
async _runJobInWorker(index, jobDispatcher) {
|
|
5571
6036
|
const job = jobDispatcher.job;
|
|
@@ -5643,8 +6108,7 @@ var Dispatcher = class {
|
|
|
5643
6108
|
void this.stop();
|
|
5644
6109
|
for (let i = 0; i < this._testRun.config.config.workers; i++)
|
|
5645
6110
|
this._workerSlots.push({});
|
|
5646
|
-
|
|
5647
|
-
this._scheduleJob();
|
|
6111
|
+
this._scheduleJobs();
|
|
5648
6112
|
this._checkFinished();
|
|
5649
6113
|
await this._finished;
|
|
5650
6114
|
}
|
|
@@ -5786,19 +6250,23 @@ var JobDispatcher = class {
|
|
|
5786
6250
|
const parentStep = params.parentStepId ? steps.get(params.parentStepId) : void 0;
|
|
5787
6251
|
const step = {
|
|
5788
6252
|
title: params.title,
|
|
6253
|
+
subtitle: params.subtitle,
|
|
5789
6254
|
titlePath: () => {
|
|
5790
6255
|
const parentPath = parentStep?.titlePath() || [];
|
|
5791
6256
|
return [...parentPath, params.title];
|
|
5792
6257
|
},
|
|
5793
6258
|
parent: parentStep,
|
|
5794
6259
|
category: params.category,
|
|
6260
|
+
params: params.params,
|
|
5795
6261
|
startTime: new Date(params.wallTime),
|
|
5796
6262
|
duration: -1,
|
|
5797
6263
|
steps: [],
|
|
5798
6264
|
attachments: [],
|
|
5799
6265
|
annotations: [],
|
|
5800
6266
|
location: params.location,
|
|
5801
|
-
_stepId: params.stepId
|
|
6267
|
+
_stepId: params.stepId,
|
|
6268
|
+
_apiName: params.apiName,
|
|
6269
|
+
_channelMethod: params.channelMethod
|
|
5802
6270
|
};
|
|
5803
6271
|
steps.set(params.stepId, step);
|
|
5804
6272
|
(parentStep || result).steps.push(step);
|
|
@@ -5980,7 +6448,7 @@ var JobDispatcher = class {
|
|
|
5980
6448
|
addLocationAndSnippetToError(this._testRun.config.config, response.error);
|
|
5981
6449
|
return response;
|
|
5982
6450
|
} catch (e) {
|
|
5983
|
-
const error = (0,
|
|
6451
|
+
const error = (0, import_util12.serializeError)(e);
|
|
5984
6452
|
addLocationAndSnippetToError(this._testRun.config.config, error);
|
|
5985
6453
|
return { response: void 0, error };
|
|
5986
6454
|
}
|
|
@@ -6099,7 +6567,7 @@ var FixedNodeSIGINTHandler = class {
|
|
|
6099
6567
|
};
|
|
6100
6568
|
|
|
6101
6569
|
// packages/playwright/src/runner/taskRunner.ts
|
|
6102
|
-
var
|
|
6570
|
+
var import_util13 = require("../util");
|
|
6103
6571
|
var colors5 = require("playwright-core/lib/utilsBundle").colors;
|
|
6104
6572
|
var debug4 = require("playwright-core/lib/utilsBundle").debug;
|
|
6105
6573
|
var { ManualPromise: ManualPromise4 } = require("playwright-core/lib/coreBundle").iso;
|
|
@@ -6140,7 +6608,7 @@ var TaskRunner = class _TaskRunner {
|
|
|
6140
6608
|
await task.setup?.(context, errors, softErrors);
|
|
6141
6609
|
} catch (e) {
|
|
6142
6610
|
debug4("pw:test:task")(`error in "${task.title}": `, e);
|
|
6143
|
-
errors.push((0,
|
|
6611
|
+
errors.push((0, import_util13.serializeError)(e));
|
|
6144
6612
|
} finally {
|
|
6145
6613
|
for (const error of [...softErrors, ...errors])
|
|
6146
6614
|
this._reporter.onError?.(error);
|
|
@@ -6202,7 +6670,7 @@ var TimeoutWatcher = class {
|
|
|
6202
6670
|
|
|
6203
6671
|
// packages/playwright/src/runner/vcs.ts
|
|
6204
6672
|
var import_child_process2 = __toESM(require("child_process"));
|
|
6205
|
-
var
|
|
6673
|
+
var import_path15 = __toESM(require("path"));
|
|
6206
6674
|
var import_common8 = require("../common");
|
|
6207
6675
|
async function detectChangedTestFiles(baseCommit, configDir) {
|
|
6208
6676
|
function gitFileList(args) {
|
|
@@ -6232,20 +6700,20 @@ async function detectChangedTestFiles(baseCommit, configDir) {
|
|
|
6232
6700
|
].join("\n"));
|
|
6233
6701
|
}
|
|
6234
6702
|
}
|
|
6235
|
-
const untrackedFiles = gitFileList(["ls-files", "--others", "--exclude-standard"]).map((file) =>
|
|
6703
|
+
const untrackedFiles = gitFileList(["ls-files", "--others", "--exclude-standard"]).map((file) => import_path15.default.join(configDir, file));
|
|
6236
6704
|
const [gitRoot] = gitFileList(["rev-parse", "--show-toplevel"]);
|
|
6237
|
-
const trackedFilesWithChanges = gitFileList(["diff", baseCommit, "--name-only"]).map((file) =>
|
|
6705
|
+
const trackedFilesWithChanges = gitFileList(["diff", baseCommit, "--name-only"]).map((file) => import_path15.default.join(gitRoot, file));
|
|
6238
6706
|
return new Set(import_common8.cc.affectedTestFiles([...untrackedFiles, ...trackedFilesWithChanges]));
|
|
6239
6707
|
}
|
|
6240
6708
|
|
|
6241
6709
|
// packages/playwright/src/runner/tasks.ts
|
|
6242
6710
|
var import_common9 = require("../common");
|
|
6243
|
-
var
|
|
6711
|
+
var import_util15 = require("../util");
|
|
6244
6712
|
var debug5 = require("playwright-core/lib/utilsBundle").debug;
|
|
6245
6713
|
var { ManualPromise: ManualPromise5 } = require("playwright-core/lib/coreBundle").iso;
|
|
6246
6714
|
var { monotonicTime: monotonicTime6 } = require("playwright-core/lib/coreBundle").iso;
|
|
6247
6715
|
var { removeFolders: removeFolders4 } = require("playwright-core/lib/coreBundle").utils;
|
|
6248
|
-
var readDirAsync2 = (0,
|
|
6716
|
+
var readDirAsync2 = (0, import_util14.promisify)(import_fs12.default.readdir);
|
|
6249
6717
|
var TestRun = class {
|
|
6250
6718
|
constructor(config2, reporter, options) {
|
|
6251
6719
|
this.rootSuite = void 0;
|
|
@@ -6316,7 +6784,6 @@ function createRunTestsTasks(config2) {
|
|
|
6316
6784
|
return [
|
|
6317
6785
|
createPhasesTask(),
|
|
6318
6786
|
createReportBeginTask(),
|
|
6319
|
-
...config2.plugins.map((plugin) => createPluginBeginTask(plugin)),
|
|
6320
6787
|
createRunTestsTask()
|
|
6321
6788
|
];
|
|
6322
6789
|
}
|
|
@@ -6324,9 +6791,7 @@ function createClearCacheTask(config2) {
|
|
|
6324
6791
|
return {
|
|
6325
6792
|
title: "clear cache",
|
|
6326
6793
|
setup: async () => {
|
|
6327
|
-
await (0,
|
|
6328
|
-
for (const plugin of config2.plugins)
|
|
6329
|
-
await plugin.instance?.clearCache?.();
|
|
6794
|
+
await (0, import_util15.removeDirAndLogToConsole)(import_common9.cc.cacheDir);
|
|
6330
6795
|
}
|
|
6331
6796
|
};
|
|
6332
6797
|
}
|
|
@@ -6355,17 +6820,6 @@ function createPluginSetupTasks(config2) {
|
|
|
6355
6820
|
}
|
|
6356
6821
|
}));
|
|
6357
6822
|
}
|
|
6358
|
-
function createPluginBeginTask(plugin) {
|
|
6359
|
-
return {
|
|
6360
|
-
title: "plugin begin",
|
|
6361
|
-
setup: async (testRun) => {
|
|
6362
|
-
await plugin.instance?.begin?.(testRun.rootSuite);
|
|
6363
|
-
},
|
|
6364
|
-
teardown: async () => {
|
|
6365
|
-
await plugin.instance?.end?.();
|
|
6366
|
-
}
|
|
6367
|
-
};
|
|
6368
|
-
}
|
|
6369
6823
|
function createGlobalSetupTask(file, config2) {
|
|
6370
6824
|
let title = "global setup";
|
|
6371
6825
|
if (config2.globalSetups.length > 1)
|
|
@@ -6408,7 +6862,7 @@ function createRemoveOutputDirsTask() {
|
|
|
6408
6862
|
return;
|
|
6409
6863
|
if (error.code === "EBUSY") {
|
|
6410
6864
|
const entries = await readDirAsync2(outputDir).catch((e) => []);
|
|
6411
|
-
await Promise.all(entries.map((entry) => removeFolders4([
|
|
6865
|
+
await Promise.all(entries.map((entry) => removeFolders4([import_path16.default.join(outputDir, entry)])));
|
|
6412
6866
|
} else {
|
|
6413
6867
|
throw error;
|
|
6414
6868
|
}
|
|
@@ -6427,7 +6881,7 @@ function createListFilesTask() {
|
|
|
6427
6881
|
projectSuite._fullProject = project;
|
|
6428
6882
|
testRun.rootSuite._addSuite(projectSuite);
|
|
6429
6883
|
const suites = files.map((file) => {
|
|
6430
|
-
const title =
|
|
6884
|
+
const title = import_path16.default.relative(testRun.config.config.rootDir, file);
|
|
6431
6885
|
const suite = new import_common9.test.Suite(title, "file");
|
|
6432
6886
|
suite.location = { file, line: 0, column: 0 };
|
|
6433
6887
|
projectSuite._addSuite(suite);
|
|
@@ -6457,8 +6911,8 @@ function createLoadTask(mode, options) {
|
|
|
6457
6911
|
testRun.preOnlyTestFilters.push((test) => !testFilter(test));
|
|
6458
6912
|
}
|
|
6459
6913
|
if (testRun.options.grep || testRun.options.grepInvert) {
|
|
6460
|
-
const grepMatcher = testRun.options.grep ? (0,
|
|
6461
|
-
const grepInvertMatcher = testRun.options.grepInvert ? (0,
|
|
6914
|
+
const grepMatcher = testRun.options.grep ? (0, import_util15.createTitleMatcher)((0, import_util15.forceRegExp)(testRun.options.grep)) : () => true;
|
|
6915
|
+
const grepInvertMatcher = testRun.options.grepInvert ? (0, import_util15.createTitleMatcher)((0, import_util15.forceRegExp)(testRun.options.grepInvert)) : () => false;
|
|
6462
6916
|
testRun.preOnlyTestFilters.push((test) => {
|
|
6463
6917
|
const grepTitle = test._grepTitleWithTags();
|
|
6464
6918
|
return !grepInvertMatcher(grepTitle) && grepMatcher(grepTitle);
|
|
@@ -6470,10 +6924,6 @@ function createLoadTask(mode, options) {
|
|
|
6470
6924
|
}
|
|
6471
6925
|
await collectProjectsAndTestFiles(testRun, !!options.doNotRunDepsOutsideProjectFilter);
|
|
6472
6926
|
await loadFileSuites(testRun, mode, options.failOnLoadErrors ? errors : softErrors);
|
|
6473
|
-
if (testRun.options.onlyChanged || options.populateDependencies) {
|
|
6474
|
-
for (const plugin of testRun.config.plugins)
|
|
6475
|
-
await plugin.instance?.populateDependencies?.();
|
|
6476
|
-
}
|
|
6477
6927
|
if (testRun.options.onlyChanged) {
|
|
6478
6928
|
const changedFiles = await detectChangedTestFiles(testRun.options.onlyChanged, testRun.config.configDir);
|
|
6479
6929
|
testRun.preOnlyTestFilters.push((test) => changedFiles.has(test.location.file));
|
|
@@ -6597,25 +7047,32 @@ function createRunTestsTask() {
|
|
|
6597
7047
|
}
|
|
6598
7048
|
|
|
6599
7049
|
// packages/playwright/src/runner/lastRun.ts
|
|
6600
|
-
var
|
|
6601
|
-
var
|
|
7050
|
+
var import_fs13 = __toESM(require("fs"));
|
|
7051
|
+
var import_path17 = __toESM(require("path"));
|
|
7052
|
+
function didNotRun(test) {
|
|
7053
|
+
if (test.outcome() !== "skipped")
|
|
7054
|
+
return false;
|
|
7055
|
+
if (test.results.some((result) => result.status === "interrupted"))
|
|
7056
|
+
return false;
|
|
7057
|
+
return !test.results.length || test.expectedStatus !== "skipped";
|
|
7058
|
+
}
|
|
6602
7059
|
var LastRunReporter = class {
|
|
6603
7060
|
constructor(filteredProjects, listMode, lastFailedFileOverride) {
|
|
6604
7061
|
this._listMode = !!listMode;
|
|
6605
7062
|
const override = lastFailedFileOverride ?? process.env.PLAYWRIGHT_LAST_RUN_OUTPUT_FILE;
|
|
6606
7063
|
if (override) {
|
|
6607
|
-
this._lastRunFile =
|
|
7064
|
+
this._lastRunFile = import_path17.default.resolve(process.cwd(), override);
|
|
6608
7065
|
} else {
|
|
6609
7066
|
const [project] = filteredProjects;
|
|
6610
7067
|
if (project)
|
|
6611
|
-
this._lastRunFile =
|
|
7068
|
+
this._lastRunFile = import_path17.default.join(project.project.outputDir, ".last-run.json");
|
|
6612
7069
|
}
|
|
6613
7070
|
}
|
|
6614
7071
|
async filterLastFailed() {
|
|
6615
7072
|
if (!this._lastRunFile)
|
|
6616
7073
|
return void 0;
|
|
6617
7074
|
try {
|
|
6618
|
-
const lastRunInfo = JSON.parse(await
|
|
7075
|
+
const lastRunInfo = JSON.parse(await import_fs13.default.promises.readFile(this._lastRunFile, "utf8"));
|
|
6619
7076
|
return lastRunInfo.failedTests;
|
|
6620
7077
|
} catch {
|
|
6621
7078
|
return void 0;
|
|
@@ -6635,10 +7092,10 @@ var LastRunReporter = class {
|
|
|
6635
7092
|
return;
|
|
6636
7093
|
const lastRunInfo = {
|
|
6637
7094
|
status: result.status,
|
|
6638
|
-
failedTests: this._suite?.allTests().filter((t2) => !t2.ok()).map((t2) => t2.id) || []
|
|
7095
|
+
failedTests: this._suite?.allTests().filter((t2) => !t2.ok() || didNotRun(t2)).map((t2) => t2.id) || []
|
|
6639
7096
|
};
|
|
6640
|
-
await
|
|
6641
|
-
await
|
|
7097
|
+
await import_fs13.default.promises.mkdir(import_path17.default.dirname(this._lastRunFile), { recursive: true });
|
|
7098
|
+
await import_fs13.default.promises.writeFile(this._lastRunFile, JSON.stringify(lastRunInfo, void 0, 2));
|
|
6642
7099
|
}
|
|
6643
7100
|
};
|
|
6644
7101
|
|
|
@@ -6658,7 +7115,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6658
7115
|
this._watchedTestDependencies = /* @__PURE__ */ new Set();
|
|
6659
7116
|
this._queue = Promise.resolve();
|
|
6660
7117
|
this._watchTestDirs = false;
|
|
6661
|
-
this._populateDependenciesOnList = false;
|
|
6662
7118
|
this._startingEnv = {};
|
|
6663
7119
|
this.configLocation = configLocation;
|
|
6664
7120
|
this._configCLIOverrides = configCLIOverrides;
|
|
@@ -6671,7 +7127,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6671
7127
|
async initialize(params) {
|
|
6672
7128
|
setPlaywrightTestProcessEnv();
|
|
6673
7129
|
this._watchTestDirs = !!params.watchTestDirs;
|
|
6674
|
-
this._populateDependenciesOnList = !!params.populateDependenciesOnList;
|
|
6675
7130
|
this._startingEnv = { ...process.env };
|
|
6676
7131
|
}
|
|
6677
7132
|
resizeTerminal(params) {
|
|
@@ -6683,7 +7138,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6683
7138
|
hasSomeBrowsers() {
|
|
6684
7139
|
for (const browserName of ["chromium", "webkit", "firefox"]) {
|
|
6685
7140
|
try {
|
|
6686
|
-
|
|
7141
|
+
import_coreBundle3.registry.registry.findExecutable(browserName).executablePathOrDie("javascript");
|
|
6687
7142
|
return true;
|
|
6688
7143
|
} catch {
|
|
6689
7144
|
}
|
|
@@ -6691,8 +7146,8 @@ var TestRunner = class extends import_events2.default {
|
|
|
6691
7146
|
return false;
|
|
6692
7147
|
}
|
|
6693
7148
|
async installBrowsers() {
|
|
6694
|
-
const executables =
|
|
6695
|
-
await
|
|
7149
|
+
const executables = import_coreBundle3.registry.registry.defaultExecutables();
|
|
7150
|
+
await import_coreBundle3.registry.registry.install(executables);
|
|
6696
7151
|
}
|
|
6697
7152
|
async loadConfig() {
|
|
6698
7153
|
const { config: config2, error } = await this._loadConfig(this._configCLIOverrides);
|
|
@@ -6732,7 +7187,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6732
7187
|
if (!config2)
|
|
6733
7188
|
return { status: "failed" };
|
|
6734
7189
|
const status = await runTasks(new TestRun(config2, reporter), [
|
|
6735
|
-
...createPluginSetupTasks(config2),
|
|
6736
7190
|
createClearCacheTask(config2)
|
|
6737
7191
|
]);
|
|
6738
7192
|
return { status };
|
|
@@ -6779,7 +7233,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6779
7233
|
listMode: true
|
|
6780
7234
|
};
|
|
6781
7235
|
const status = await runTasks(new TestRun(config2, reporter, options), [
|
|
6782
|
-
createLoadTask("out-of-process", { failOnLoadErrors: false, filterOnly: false
|
|
7236
|
+
createLoadTask("out-of-process", { failOnLoadErrors: false, filterOnly: false }),
|
|
6783
7237
|
createReportBeginTask()
|
|
6784
7238
|
]);
|
|
6785
7239
|
return { config: config2, status };
|
|
@@ -6791,11 +7245,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6791
7245
|
this._watchedProjectDirs.add(p.project.testDir);
|
|
6792
7246
|
this._ignoredProjectOutputs.add(p.project.outputDir);
|
|
6793
7247
|
}
|
|
6794
|
-
const result = await resolveCtDirs(config2);
|
|
6795
|
-
if (result) {
|
|
6796
|
-
this._watchedProjectDirs.add(result.templateDir);
|
|
6797
|
-
this._ignoredProjectOutputs.add(result.outDir);
|
|
6798
|
-
}
|
|
6799
7248
|
if (this._watchTestDirs)
|
|
6800
7249
|
await this._updateWatcher(false);
|
|
6801
7250
|
}
|
|
@@ -6886,7 +7335,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6886
7335
|
return { errors: errorReporter.errors(), testFiles: [] };
|
|
6887
7336
|
const status = await runTasks(new TestRun(config2, reporter), [
|
|
6888
7337
|
...createPluginSetupTasks(config2),
|
|
6889
|
-
createLoadTask("out-of-process", { failOnLoadErrors: true, filterOnly: false
|
|
7338
|
+
createLoadTask("out-of-process", { failOnLoadErrors: true, filterOnly: false })
|
|
6890
7339
|
]);
|
|
6891
7340
|
if (status !== "passed")
|
|
6892
7341
|
return { errors: errorReporter.errors(), testFiles: [] };
|
|
@@ -6915,7 +7364,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6915
7364
|
this._lastLoadedConfig = config2;
|
|
6916
7365
|
return { config: config2 };
|
|
6917
7366
|
} catch (e) {
|
|
6918
|
-
return { config: null, error: (0,
|
|
7367
|
+
return { config: null, error: (0, import_util16.serializeError)(e) };
|
|
6919
7368
|
}
|
|
6920
7369
|
}
|
|
6921
7370
|
lastLoadedConfig() {
|
|
@@ -6935,18 +7384,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6935
7384
|
function printInternalError(e) {
|
|
6936
7385
|
console.error("Internal error:", e);
|
|
6937
7386
|
}
|
|
6938
|
-
async function resolveCtDirs(config2) {
|
|
6939
|
-
const use = config2.config.projects[0].use;
|
|
6940
|
-
const relativeTemplateDir = use.ctTemplateDir || "playwright";
|
|
6941
|
-
const templateDir = await import_fs13.default.promises.realpath(import_path17.default.normalize(import_path17.default.join(config2.configDir, relativeTemplateDir))).catch(() => void 0);
|
|
6942
|
-
if (!templateDir)
|
|
6943
|
-
return null;
|
|
6944
|
-
const outDir = use.ctCacheDir ? import_path17.default.resolve(config2.configDir, use.ctCacheDir) : import_path17.default.resolve(templateDir, ".cache");
|
|
6945
|
-
return {
|
|
6946
|
-
outDir,
|
|
6947
|
-
templateDir
|
|
6948
|
-
};
|
|
6949
|
-
}
|
|
6950
7387
|
async function runAllTestsWithConfig(config2, options) {
|
|
6951
7388
|
setPlaywrightTestProcessEnv();
|
|
6952
7389
|
addGitCommitInfoPlugin(config2);
|
|
@@ -6983,8 +7420,8 @@ __export(testServer_exports, {
|
|
|
6983
7420
|
runTestServer: () => runTestServer,
|
|
6984
7421
|
runUIMode: () => runUIMode
|
|
6985
7422
|
});
|
|
6986
|
-
var
|
|
6987
|
-
var
|
|
7423
|
+
var import_util17 = __toESM(require("util"));
|
|
7424
|
+
var import_coreBundle4 = require("playwright-core/lib/coreBundle");
|
|
6988
7425
|
var import_common11 = require("../common");
|
|
6989
7426
|
|
|
6990
7427
|
// packages/playwright/src/runner/uiModeReporter.ts
|
|
@@ -7013,7 +7450,7 @@ var TestServer = class {
|
|
|
7013
7450
|
}
|
|
7014
7451
|
async start(options) {
|
|
7015
7452
|
this._dispatcher = new TestServerDispatcher(this._configLocation, this._configCLIOverrides);
|
|
7016
|
-
return await
|
|
7453
|
+
return await import_coreBundle4.server.startTraceViewerServer({
|
|
7017
7454
|
host: options.host,
|
|
7018
7455
|
port: options.port,
|
|
7019
7456
|
allowedFileRoots: () => this._allowedFileRoots(),
|
|
@@ -7143,7 +7580,7 @@ var TestServerDispatcher = class {
|
|
|
7143
7580
|
if (interceptStdio) {
|
|
7144
7581
|
if (debug6.log === originalDebugLog) {
|
|
7145
7582
|
debug6.log = (...args) => {
|
|
7146
|
-
const string =
|
|
7583
|
+
const string = import_util17.default.format(...args) + "\n";
|
|
7147
7584
|
return originalStderrWrite.apply(process.stderr, [string]);
|
|
7148
7585
|
};
|
|
7149
7586
|
}
|
|
@@ -7169,12 +7606,12 @@ var TestServerDispatcher = class {
|
|
|
7169
7606
|
async function runUIMode(configFile, configCLIOverrides, options) {
|
|
7170
7607
|
const configLocation = import_common11.configLoader.resolveConfigLocation(configFile);
|
|
7171
7608
|
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server, cancelPromise) => {
|
|
7172
|
-
await
|
|
7609
|
+
await import_coreBundle4.server.installRootRedirect(server, void 0, { ...options, webApp: "uiMode.html" });
|
|
7173
7610
|
if (options.host !== void 0 || options.port !== void 0) {
|
|
7174
|
-
await
|
|
7611
|
+
await import_coreBundle4.server.openTraceInBrowser(server.urlPrefix("human-readable"));
|
|
7175
7612
|
} else {
|
|
7176
7613
|
const channel = await installedChromiumChannelForUI(configLocation, configCLIOverrides);
|
|
7177
|
-
const page = await
|
|
7614
|
+
const page = await import_coreBundle4.server.openTraceViewerApp(server.urlPrefix("precise"), "chromium", {
|
|
7178
7615
|
headless: isUnderTest() && process.env.PWTEST_HEADED_FOR_TEST !== "1",
|
|
7179
7616
|
persistentContextOptions: {
|
|
7180
7617
|
handleSIGINT: false,
|
|
@@ -7239,7 +7676,7 @@ __export(watchMode_exports, {
|
|
|
7239
7676
|
var import_path18 = __toESM(require("path"));
|
|
7240
7677
|
var import_readline = __toESM(require("readline"));
|
|
7241
7678
|
var import_events3 = require("events");
|
|
7242
|
-
var
|
|
7679
|
+
var import_coreBundle5 = require("playwright-core/lib/coreBundle");
|
|
7243
7680
|
|
|
7244
7681
|
// packages/playwright/src/isomorphic/testTree.ts
|
|
7245
7682
|
var statusEx = /* @__PURE__ */ Symbol("statusEx");
|
|
@@ -7658,8 +8095,7 @@ async function runWatchModeLoop(configLocation, initialOptions) {
|
|
|
7658
8095
|
testServerConnection.onReport((report2) => teleSuiteUpdater.processTestReportEvent(report2));
|
|
7659
8096
|
await testServerConnection.initialize({
|
|
7660
8097
|
interceptStdio: false,
|
|
7661
|
-
watchTestDirs: true
|
|
7662
|
-
populateDependenciesOnList: true
|
|
8098
|
+
watchTestDirs: true
|
|
7663
8099
|
});
|
|
7664
8100
|
await testServerConnection.runGlobalSetup({});
|
|
7665
8101
|
const { report } = await testServerConnection.listTests({});
|
|
@@ -7921,7 +8357,7 @@ ${colors6.dim("Waiting for file changes. Press")} ${colors6.bold("enter")} ${col
|
|
|
7921
8357
|
}
|
|
7922
8358
|
async function toggleShowBrowser() {
|
|
7923
8359
|
if (!showBrowserServer) {
|
|
7924
|
-
showBrowserServer = new
|
|
8360
|
+
showBrowserServer = new import_coreBundle5.remote.PlaywrightServer({ mode: "extension", path: "/" + createGuid3(), maxConnections: 1 });
|
|
7925
8361
|
connectWsEndpoint = await showBrowserServer.listen();
|
|
7926
8362
|
process.stdout.write(`${colors6.dim("Show & reuse browser:")} ${colors6.bold("on")}
|
|
7927
8363
|
`);
|
|
@@ -7985,7 +8421,7 @@ var JsonStringInternalizer = class {
|
|
|
7985
8421
|
};
|
|
7986
8422
|
|
|
7987
8423
|
// packages/playwright/src/reporters/merge.ts
|
|
7988
|
-
var
|
|
8424
|
+
var import_util18 = require("../util");
|
|
7989
8425
|
var { isPathInside } = require("playwright-core/lib/coreBundle").utils;
|
|
7990
8426
|
var { ZipFile } = require("playwright-core/lib/coreBundle").utils;
|
|
7991
8427
|
async function createMergedReport(config2, dir, reporterDescriptions, rootDirOverride) {
|
|
@@ -8081,7 +8517,7 @@ async function extractAndParseReports(dir, shardFiles, internalizer, printStatus
|
|
|
8081
8517
|
const reportNames = new UniqueFileNameGenerator();
|
|
8082
8518
|
for (const file of shardFiles) {
|
|
8083
8519
|
const absolutePath = import_path19.default.join(dir, file);
|
|
8084
|
-
printStatus(`extracting: ${(0,
|
|
8520
|
+
printStatus(`extracting: ${(0, import_util18.relativeFilePath)(absolutePath)}`);
|
|
8085
8521
|
const zipFile = new ZipFile(absolutePath);
|
|
8086
8522
|
const entryNames = await zipFile.entries();
|
|
8087
8523
|
for (const entryName of entryNames.sort()) {
|