@smoothdeploy/playwright 1.62.1 → 1.63.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/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 +36 -25
- 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 +767 -321
- 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 +2 -5
- 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
|
+
|
|
5193
|
+
// packages/playwright/src/reporters/smoothdeploy.ts
|
|
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
|
+
|
|
4891
5298
|
// packages/playwright/src/reporters/smoothdeploy.ts
|
|
4892
|
-
var
|
|
4893
|
-
var
|
|
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,46 @@ 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 manifestTest = this._findManifestTest(test);
|
|
5344
|
+
if (!manifestTest)
|
|
5345
|
+
return { manifestTest: { id: test.id, title: test.title, steps: [] }, paramIndex: 0, passthrough: true };
|
|
5346
|
+
const single = manifestTest.manifestTest.steps.length === 1 ? manifestTest.manifestTest.steps[0] : void 0;
|
|
5347
|
+
if (single && single.action === "script")
|
|
5348
|
+
return { ...manifestTest, passthrough: true, passthroughRootId: single.id };
|
|
5349
|
+
return { ...manifestTest, passthrough: false };
|
|
5350
|
+
}
|
|
5351
|
+
_findManifestTest(test) {
|
|
4960
5352
|
if (!this._manifest)
|
|
4961
5353
|
return null;
|
|
4962
5354
|
const titlePath = test.titlePath();
|
|
4963
|
-
const relFile =
|
|
5355
|
+
const relFile = path13.relative(this._configDir, test.location.file);
|
|
4964
5356
|
const fileManifest = this._manifest.files[relFile];
|
|
4965
5357
|
if (!fileManifest)
|
|
4966
5358
|
return null;
|
|
4967
5359
|
const fileIdx = titlePath.indexOf(relFile);
|
|
4968
5360
|
const describeTitles = fileIdx >= 0 ? titlePath.slice(fileIdx + 1, -1) : [];
|
|
4969
|
-
const testTitle = test.title;
|
|
4970
5361
|
let currentSuites = fileManifest.suites;
|
|
4971
5362
|
let currentTests = fileManifest.tests;
|
|
4972
5363
|
for (const desc of describeTitles) {
|
|
@@ -4976,15 +5367,13 @@ var SmoothDeployReporter = class {
|
|
|
4976
5367
|
currentSuites = suite.suites;
|
|
4977
5368
|
currentTests = suite.tests;
|
|
4978
5369
|
}
|
|
4979
|
-
const exactMatch = currentTests.find((t2) => t2.title ===
|
|
5370
|
+
const exactMatch = currentTests.find((t2) => t2.title === test.title);
|
|
4980
5371
|
if (exactMatch)
|
|
4981
5372
|
return { manifestTest: exactMatch, paramIndex: 0 };
|
|
4982
5373
|
for (const mt of currentTests) {
|
|
4983
|
-
if (!mt.params || mt.params < 1)
|
|
4984
|
-
continue;
|
|
4985
|
-
if (!testTitle.startsWith(mt.title))
|
|
5374
|
+
if (!mt.params || mt.params < 1 || !test.title.startsWith(mt.title))
|
|
4986
5375
|
continue;
|
|
4987
|
-
const suffix =
|
|
5376
|
+
const suffix = test.title.slice(mt.title.length);
|
|
4988
5377
|
const idx = parseInt(suffix, 10);
|
|
4989
5378
|
if (String(idx) === suffix && idx >= 0 && idx < mt.params)
|
|
4990
5379
|
return { manifestTest: mt, paramIndex: idx };
|
|
@@ -4993,13 +5382,9 @@ var SmoothDeployReporter = class {
|
|
|
4993
5382
|
}
|
|
4994
5383
|
onTestBegin(test, result) {
|
|
4995
5384
|
const resolved = this._resolveManifestTest(test);
|
|
4996
|
-
if (!resolved)
|
|
4997
|
-
return;
|
|
4998
5385
|
this._resolvedTests.set(test.id, resolved);
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
this._testIdMap.set(safePw, safeManifest);
|
|
5002
|
-
this._childCounters.set(test.id, 0);
|
|
5386
|
+
this._testIdMap.set(safeId(test.id), safeId(resolved.manifestTest.id));
|
|
5387
|
+
this._rootCursors.set(test.id, 0);
|
|
5003
5388
|
this._testSteps.set(test.id, []);
|
|
5004
5389
|
this._emit({
|
|
5005
5390
|
event: "testBegin",
|
|
@@ -5008,11 +5393,36 @@ var SmoothDeployReporter = class {
|
|
|
5008
5393
|
testTitle: test.title,
|
|
5009
5394
|
timestamp: Date.now()
|
|
5010
5395
|
});
|
|
5396
|
+
if (resolved.passthroughRootId) {
|
|
5397
|
+
this._emit({
|
|
5398
|
+
event: "stepBegin",
|
|
5399
|
+
testId: resolved.manifestTest.id,
|
|
5400
|
+
paramIndex: resolved.paramIndex,
|
|
5401
|
+
id: resolved.passthroughRootId,
|
|
5402
|
+
action: "script",
|
|
5403
|
+
title: test.title,
|
|
5404
|
+
category: "test.step",
|
|
5405
|
+
timestamp: Date.now()
|
|
5406
|
+
});
|
|
5407
|
+
}
|
|
5011
5408
|
}
|
|
5012
5409
|
onTestEnd(test, result) {
|
|
5013
5410
|
const resolved = this._resolvedTests.get(test.id);
|
|
5014
5411
|
if (!resolved)
|
|
5015
5412
|
return;
|
|
5413
|
+
if (resolved.passthroughRootId) {
|
|
5414
|
+
this._emit({
|
|
5415
|
+
event: "stepEnd",
|
|
5416
|
+
testId: resolved.manifestTest.id,
|
|
5417
|
+
paramIndex: resolved.paramIndex,
|
|
5418
|
+
id: resolved.passthroughRootId,
|
|
5419
|
+
action: "script",
|
|
5420
|
+
title: test.title,
|
|
5421
|
+
duration: result.duration,
|
|
5422
|
+
error: result.error ? { message: result.error.message } : null,
|
|
5423
|
+
timestamp: Date.now()
|
|
5424
|
+
});
|
|
5425
|
+
}
|
|
5016
5426
|
this._emit({
|
|
5017
5427
|
event: "testEnd",
|
|
5018
5428
|
testId: resolved.manifestTest.id,
|
|
@@ -5022,29 +5432,77 @@ var SmoothDeployReporter = class {
|
|
|
5022
5432
|
duration: result.duration,
|
|
5023
5433
|
timestamp: Date.now()
|
|
5024
5434
|
});
|
|
5025
|
-
this.
|
|
5435
|
+
this._rootCursors.delete(test.id);
|
|
5436
|
+
}
|
|
5437
|
+
_nearestMatchedAncestor(step) {
|
|
5438
|
+
for (let p = step.parent; p; p = p.parent) {
|
|
5439
|
+
const matched = this._matched.get(p);
|
|
5440
|
+
if (matched)
|
|
5441
|
+
return { matched, blocked: false };
|
|
5442
|
+
if (this._opaqueFiller.has(p))
|
|
5443
|
+
return { blocked: true };
|
|
5444
|
+
}
|
|
5445
|
+
return { blocked: false };
|
|
5446
|
+
}
|
|
5447
|
+
_resolveStep(test, resolved, step, parent) {
|
|
5448
|
+
const stepLike = { title: step.title, category: step.category, apiName: step._apiName, channelMethod: step._channelMethod };
|
|
5449
|
+
if (resolved.passthrough) {
|
|
5450
|
+
const index2 = parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0;
|
|
5451
|
+
const prefix = parent ? `${parent.manifest.id}:` : resolved.passthroughRootId ? `${resolved.passthroughRootId}:` : "";
|
|
5452
|
+
if (parent)
|
|
5453
|
+
parent.cursor = index2 + 1;
|
|
5454
|
+
else
|
|
5455
|
+
this._rootCursors.set(test.id, index2 + 1);
|
|
5456
|
+
const action = step.category === "test.step" ? "group" : shortApi(stepLike) ?? step.category;
|
|
5457
|
+
return { id: `${prefix}${index2}`, action, title: step.title, children: [] };
|
|
5458
|
+
}
|
|
5459
|
+
if (parent && parent.manifest.children.length === 0)
|
|
5460
|
+
return null;
|
|
5461
|
+
const siblings = parent ? parent.manifest.children : resolved.manifestTest.steps;
|
|
5462
|
+
const cursor = parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0;
|
|
5463
|
+
let index = matchStep(stepLike, siblings, cursor);
|
|
5464
|
+
const retry = this._nearestRetry(step);
|
|
5465
|
+
if (index < 0 && retry && retry.parent === parent && cursor > retry.startCursor) {
|
|
5466
|
+
index = matchStep(stepLike, siblings.slice(0, cursor), retry.startCursor);
|
|
5467
|
+
if (index >= 0)
|
|
5468
|
+
this._discardAttempt(test, retry);
|
|
5469
|
+
}
|
|
5470
|
+
if (index < 0)
|
|
5471
|
+
return null;
|
|
5472
|
+
if (parent)
|
|
5473
|
+
parent.cursor = index + 1;
|
|
5474
|
+
else
|
|
5475
|
+
this._rootCursors.set(test.id, index + 1);
|
|
5476
|
+
return siblings[index];
|
|
5477
|
+
}
|
|
5478
|
+
_discardAttempt(test, retry) {
|
|
5479
|
+
const list = retry.parent ? retry.parent.output.children : this._testSteps.get(test.id);
|
|
5480
|
+
for (const output of retry.outputs) {
|
|
5481
|
+
const i = list ? list.indexOf(output) : -1;
|
|
5482
|
+
if (i >= 0)
|
|
5483
|
+
list.splice(i, 1);
|
|
5484
|
+
}
|
|
5485
|
+
retry.outputs = [];
|
|
5486
|
+
retry.events = [];
|
|
5026
5487
|
}
|
|
5027
5488
|
onStepBegin(test, result, step) {
|
|
5028
|
-
if (!
|
|
5489
|
+
if (!isUserStep(step))
|
|
5029
5490
|
return;
|
|
5030
5491
|
const resolved = this._resolvedTests.get(test.id);
|
|
5031
5492
|
if (!resolved)
|
|
5032
5493
|
return;
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
const outputStep = {
|
|
5046
|
-
id: manifestStep?.id,
|
|
5047
|
-
action: manifestStep?.action,
|
|
5494
|
+
const { matched: parent, blocked } = this._nearestMatchedAncestor(step);
|
|
5495
|
+
const manifestStep = blocked ? null : this._resolveStep(test, resolved, step, parent);
|
|
5496
|
+
if (!manifestStep) {
|
|
5497
|
+
if (blocked || !isToPassWrapper({ title: step.title, category: step.category, apiName: step._apiName }))
|
|
5498
|
+
this._opaqueFiller.add(step);
|
|
5499
|
+
else
|
|
5500
|
+
this._retries.set(step, { parent, startCursor: parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0, events: [], outputs: [] });
|
|
5501
|
+
return;
|
|
5502
|
+
}
|
|
5503
|
+
const output = {
|
|
5504
|
+
id: manifestStep.id,
|
|
5505
|
+
action: manifestStep.action,
|
|
5048
5506
|
title: step.title,
|
|
5049
5507
|
category: step.category,
|
|
5050
5508
|
duration: 0,
|
|
@@ -5052,97 +5510,106 @@ var SmoothDeployReporter = class {
|
|
|
5052
5510
|
screenshots: null,
|
|
5053
5511
|
children: []
|
|
5054
5512
|
};
|
|
5055
|
-
this.
|
|
5056
|
-
const
|
|
5057
|
-
if (
|
|
5058
|
-
|
|
5513
|
+
this._matched.set(step, { manifest: manifestStep, output, cursor: 0 });
|
|
5514
|
+
const retry = this._nearestRetry(step);
|
|
5515
|
+
if (retry && retry.parent === parent)
|
|
5516
|
+
retry.outputs.push(output);
|
|
5517
|
+
if (parent)
|
|
5518
|
+
parent.output.children.push(output);
|
|
5059
5519
|
else
|
|
5060
|
-
this._testSteps.get(test.id)?.push(
|
|
5520
|
+
this._testSteps.get(test.id)?.push(output);
|
|
5061
5521
|
this._emit({
|
|
5062
5522
|
event: "stepBegin",
|
|
5063
5523
|
testId: resolved.manifestTest.id,
|
|
5064
5524
|
paramIndex: resolved.paramIndex,
|
|
5065
|
-
id: manifestStep
|
|
5066
|
-
action: manifestStep
|
|
5525
|
+
id: manifestStep.id,
|
|
5526
|
+
action: manifestStep.action,
|
|
5067
5527
|
title: step.title,
|
|
5068
5528
|
category: step.category,
|
|
5069
5529
|
timestamp: Date.now()
|
|
5070
|
-
});
|
|
5530
|
+
}, step);
|
|
5531
|
+
}
|
|
5532
|
+
_screenshotsFor(test, step) {
|
|
5533
|
+
const hasScreenshot = step.category === "pw:api" && !NO_SCREENSHOT_PREFIXES.some((prefix) => step.title.startsWith(prefix));
|
|
5534
|
+
if (!hasScreenshot)
|
|
5535
|
+
return null;
|
|
5536
|
+
const safeStepId = safeId(step._stepId ?? step.title);
|
|
5537
|
+
return {
|
|
5538
|
+
safeStepId,
|
|
5539
|
+
paths: {
|
|
5540
|
+
page: `.smoothdeploy-output/screenshots/${safeId(test.id)}/${safeStepId}-page.png`,
|
|
5541
|
+
element: `.smoothdeploy-output/screenshots/${safeId(test.id)}/${safeStepId}-element.png`
|
|
5542
|
+
}
|
|
5543
|
+
};
|
|
5071
5544
|
}
|
|
5072
5545
|
onStepEnd(test, result, step) {
|
|
5073
|
-
if (!
|
|
5546
|
+
if (!isUserStep(step))
|
|
5074
5547
|
return;
|
|
5075
5548
|
const resolved = this._resolvedTests.get(test.id);
|
|
5076
5549
|
if (!resolved)
|
|
5077
5550
|
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);
|
|
5551
|
+
const retry = this._retries.get(step);
|
|
5552
|
+
if (retry) {
|
|
5553
|
+
this._retries.delete(step);
|
|
5554
|
+
for (const event of retry.events)
|
|
5555
|
+
this._emit(event, step);
|
|
5556
|
+
return;
|
|
5557
|
+
}
|
|
5558
|
+
const matched = this._matched.get(step);
|
|
5559
|
+
const screenshots = this._screenshotsFor(test, step);
|
|
5560
|
+
if (!matched) {
|
|
5561
|
+
const leaf = this._nearestMatchedAncestor(step).matched;
|
|
5562
|
+
if (screenshots && leaf && leaf.manifest.children.length === 0 && !leaf.output.screenshots) {
|
|
5563
|
+
this._stepIdMap.set(screenshots.safeStepId, safeId(leaf.manifest.id));
|
|
5564
|
+
leaf.output.screenshots = screenshots.paths;
|
|
5565
|
+
}
|
|
5566
|
+
return;
|
|
5567
|
+
}
|
|
5568
|
+
if (screenshots) {
|
|
5569
|
+
this._stepIdMap.set(screenshots.safeStepId, safeId(matched.manifest.id));
|
|
5570
|
+
matched.output.screenshots = screenshots.paths;
|
|
5571
|
+
}
|
|
5572
|
+
matched.output.duration = step.duration;
|
|
5573
|
+
const skipped = step.annotations.some((a) => a.type === "skip");
|
|
5574
|
+
if (skipped)
|
|
5575
|
+
matched.output.skipped = true;
|
|
5576
|
+
const hasDescendantError = (steps) => steps.some((c) => c.error !== null || hasDescendantError(c.children));
|
|
5577
|
+
matched.output.error = step.error && !hasDescendantError(matched.output.children) ? { message: step.error.message ?? "" } : null;
|
|
5109
5578
|
this._emit({
|
|
5110
5579
|
event: "stepEnd",
|
|
5111
5580
|
testId: resolved.manifestTest.id,
|
|
5112
5581
|
paramIndex: resolved.paramIndex,
|
|
5113
|
-
id:
|
|
5114
|
-
action:
|
|
5582
|
+
id: matched.manifest.id,
|
|
5583
|
+
action: matched.manifest.action,
|
|
5115
5584
|
title: step.title,
|
|
5116
5585
|
duration: step.duration,
|
|
5117
5586
|
error: step.error ? { message: step.error.message } : null,
|
|
5587
|
+
skipped,
|
|
5118
5588
|
timestamp: Date.now()
|
|
5119
|
-
});
|
|
5589
|
+
}, step);
|
|
5120
5590
|
}
|
|
5121
5591
|
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
|
-
}
|
|
5592
|
+
const outputDir = path13.join(process.cwd(), ".smoothdeploy-output");
|
|
5593
|
+
const screenshotsDir = path13.join(outputDir, "screenshots");
|
|
5594
|
+
for (const [safePwTestId] of this._testIdMap) {
|
|
5595
|
+
const testDir = path13.join(screenshotsDir, safePwTestId);
|
|
5596
|
+
if (!fs10.existsSync(testDir))
|
|
5597
|
+
continue;
|
|
5598
|
+
for (const [safePwStepId, safeManifestStepId] of this._stepIdMap) {
|
|
5599
|
+
for (const suffix of ["-page.png", "-element.png"]) {
|
|
5600
|
+
const src = path13.join(testDir, `${safePwStepId}${suffix}`);
|
|
5601
|
+
if (fs10.existsSync(src))
|
|
5602
|
+
fs10.renameSync(src, path13.join(testDir, `${safeManifestStepId}${suffix}`));
|
|
5136
5603
|
}
|
|
5137
5604
|
}
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5605
|
+
}
|
|
5606
|
+
for (const [safePwTestId, safeManifestTestId] of this._testIdMap) {
|
|
5607
|
+
const src = path13.join(screenshotsDir, safePwTestId);
|
|
5608
|
+
const dst = path13.join(screenshotsDir, safeManifestTestId);
|
|
5609
|
+
if (src !== dst && fs10.existsSync(src)) {
|
|
5610
|
+
if (fs10.existsSync(dst))
|
|
5611
|
+
fs10.rmSync(dst, { recursive: true });
|
|
5612
|
+
fs10.renameSync(src, dst);
|
|
5146
5613
|
}
|
|
5147
5614
|
}
|
|
5148
5615
|
const remapScreenshotPaths = (steps) => {
|
|
@@ -5160,24 +5627,17 @@ var SmoothDeployReporter = class {
|
|
|
5160
5627
|
if (!resolved)
|
|
5161
5628
|
continue;
|
|
5162
5629
|
remapScreenshotPaths(steps);
|
|
5163
|
-
const safeManifestTestId = resolved.manifestTest.id
|
|
5164
|
-
const failurePath =
|
|
5165
|
-
const failureScreenshot =
|
|
5630
|
+
const safeManifestTestId = safeId(resolved.manifestTest.id);
|
|
5631
|
+
const failurePath = path13.join(screenshotsDir, safeManifestTestId, "failure.png");
|
|
5632
|
+
const failureScreenshot = fs10.existsSync(failurePath) ? `.smoothdeploy-output/screenshots/${safeManifestTestId}/failure.png` : null;
|
|
5166
5633
|
const key = resolved.manifestTest.id;
|
|
5167
5634
|
if (!manifest[key])
|
|
5168
5635
|
manifest[key] = [];
|
|
5169
5636
|
manifest[key].push({ paramIndex: resolved.paramIndex, steps, failureScreenshot });
|
|
5170
5637
|
}
|
|
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
|
-
});
|
|
5638
|
+
fs10.mkdirSync(outputDir, { recursive: true });
|
|
5639
|
+
fs10.writeFileSync(path13.join(outputDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
5640
|
+
this._emit({ event: "runEnd", status: result.status, timestamp: Date.now() });
|
|
5181
5641
|
}
|
|
5182
5642
|
_remapPath(screenshotPath) {
|
|
5183
5643
|
let result = screenshotPath;
|
|
@@ -5194,21 +5654,20 @@ var smoothdeploy_default = SmoothDeployReporter;
|
|
|
5194
5654
|
var { calculateSha1: calculateSha13 } = require("playwright-core/lib/coreBundle").utils;
|
|
5195
5655
|
async function createReporters(config2, mode, descriptions, runOptions) {
|
|
5196
5656
|
const defaultReporters = {
|
|
5197
|
-
blob: BlobReporter,
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5657
|
+
"blob": BlobReporter,
|
|
5658
|
+
"perfetto": perfetto_default,
|
|
5659
|
+
"dot": mode === "list" ? listModeReporter_default : dot_default,
|
|
5660
|
+
"line": mode === "list" ? listModeReporter_default : line_default,
|
|
5661
|
+
"list": mode === "list" ? listModeReporter_default : list_default,
|
|
5662
|
+
"github": github_default,
|
|
5663
|
+
"json": json_default,
|
|
5664
|
+
"junit": junit_default,
|
|
5665
|
+
"null": empty_default,
|
|
5666
|
+
"html": html_default,
|
|
5667
|
+
"smoothdeploy": smoothdeploy_default
|
|
5207
5668
|
};
|
|
5208
5669
|
const reporters = [];
|
|
5209
5670
|
descriptions ??= config2.config.reporter;
|
|
5210
|
-
if (runOptions?.additionalReporters)
|
|
5211
|
-
descriptions = [...descriptions, ...runOptions.additionalReporters];
|
|
5212
5671
|
const reportOptions = reporterCommandOptions(config2, mode, runOptions);
|
|
5213
5672
|
for (const r of descriptions) {
|
|
5214
5673
|
const [name, arg] = r;
|
|
@@ -5272,22 +5731,22 @@ function computeCommandHash(config2, runOptions) {
|
|
|
5272
5731
|
if (config2.config.tags.length)
|
|
5273
5732
|
command.tags = config2.config.tags.join(" ");
|
|
5274
5733
|
if (runOptions?.testList)
|
|
5275
|
-
command.testList = calculateSha13(
|
|
5734
|
+
command.testList = calculateSha13(import_fs9.default.readFileSync(runOptions.testList));
|
|
5276
5735
|
if (runOptions?.testListInvert)
|
|
5277
|
-
command.testListInvert = calculateSha13(
|
|
5736
|
+
command.testListInvert = calculateSha13(import_fs9.default.readFileSync(runOptions.testListInvert));
|
|
5278
5737
|
if (Object.keys(command).length)
|
|
5279
5738
|
parts.push(calculateSha13(JSON.stringify(command)).substring(0, 7));
|
|
5280
5739
|
return parts.join("-");
|
|
5281
5740
|
}
|
|
5282
5741
|
|
|
5283
5742
|
// packages/playwright/src/runner/tasks.ts
|
|
5284
|
-
var
|
|
5285
|
-
var
|
|
5286
|
-
var
|
|
5743
|
+
var import_fs12 = __toESM(require("fs"));
|
|
5744
|
+
var import_path16 = __toESM(require("path"));
|
|
5745
|
+
var import_util14 = require("util");
|
|
5287
5746
|
|
|
5288
5747
|
// packages/playwright/src/runner/rebase.ts
|
|
5289
|
-
var
|
|
5290
|
-
var
|
|
5748
|
+
var import_fs10 = __toESM(require("fs"));
|
|
5749
|
+
var import_path13 = __toESM(require("path"));
|
|
5291
5750
|
var babel3 = __toESM(require("../transform/babelBundle"));
|
|
5292
5751
|
var colors3 = require("playwright-core/lib/utilsBundle").colors;
|
|
5293
5752
|
var diff = require("playwright-core/lib/utilsBundle").diff;
|
|
@@ -5311,9 +5770,9 @@ async function applySuggestedRebaselines(config2, reporter, filteredProjects) {
|
|
|
5311
5770
|
const patches = [];
|
|
5312
5771
|
const files = [];
|
|
5313
5772
|
const gitCache = /* @__PURE__ */ new Map();
|
|
5314
|
-
const patchFile =
|
|
5773
|
+
const patchFile = import_path13.default.join(project.project.outputDir, "rebaselines.patch");
|
|
5315
5774
|
for (const fileName of [...suggestedRebaselines.keys()].sort()) {
|
|
5316
|
-
const source = await
|
|
5775
|
+
const source = await import_fs10.default.promises.readFile(fileName, "utf8");
|
|
5317
5776
|
const lines = source.split("\n");
|
|
5318
5777
|
const replacements = suggestedRebaselines.get(fileName);
|
|
5319
5778
|
const fileNode = babel3.babelParse(source, fileName, true);
|
|
@@ -5347,15 +5806,15 @@ async function applySuggestedRebaselines(config2, reporter, filteredProjects) {
|
|
|
5347
5806
|
let result = source;
|
|
5348
5807
|
for (const range of ranges)
|
|
5349
5808
|
result = result.substring(0, range.start) + range.newText + result.substring(range.end);
|
|
5350
|
-
const relativeName =
|
|
5809
|
+
const relativeName = import_path13.default.relative(process.cwd(), fileName);
|
|
5351
5810
|
files.push(relativeName);
|
|
5352
5811
|
if (config2.config.updateSourceMethod === "overwrite") {
|
|
5353
|
-
await
|
|
5812
|
+
await import_fs10.default.promises.writeFile(fileName, result);
|
|
5354
5813
|
} else if (config2.config.updateSourceMethod === "3way") {
|
|
5355
|
-
await
|
|
5814
|
+
await import_fs10.default.promises.writeFile(fileName, applyPatchWithConflictMarkers(source, result));
|
|
5356
5815
|
} else {
|
|
5357
|
-
const gitFolder = findGitRoot(
|
|
5358
|
-
const relativeToGit =
|
|
5816
|
+
const gitFolder = findGitRoot(import_path13.default.dirname(fileName), gitCache);
|
|
5817
|
+
const relativeToGit = import_path13.default.relative(gitFolder || process.cwd(), fileName);
|
|
5359
5818
|
patches.push(createPatch(relativeToGit, source, result));
|
|
5360
5819
|
}
|
|
5361
5820
|
}
|
|
@@ -5366,10 +5825,10 @@ New baselines created for:
|
|
|
5366
5825
|
${fileList}
|
|
5367
5826
|
`);
|
|
5368
5827
|
if (config2.config.updateSourceMethod === "patch") {
|
|
5369
|
-
await
|
|
5370
|
-
await
|
|
5828
|
+
await import_fs10.default.promises.mkdir(import_path13.default.dirname(patchFile), { recursive: true });
|
|
5829
|
+
await import_fs10.default.promises.writeFile(patchFile, patches.join("\n"));
|
|
5371
5830
|
reporter.onStdErr(`
|
|
5372
|
-
` + colors3.cyan("git apply " +
|
|
5831
|
+
` + colors3.cyan("git apply " + import_path13.default.relative(process.cwd(), patchFile)) + "\n");
|
|
5373
5832
|
}
|
|
5374
5833
|
}
|
|
5375
5834
|
function createPatch(fileName, before, after) {
|
|
@@ -5386,12 +5845,12 @@ function findGitRoot(dir, cache) {
|
|
|
5386
5845
|
const result = cache.get(dir);
|
|
5387
5846
|
if (result !== void 0)
|
|
5388
5847
|
return result;
|
|
5389
|
-
const gitPath =
|
|
5390
|
-
if (
|
|
5848
|
+
const gitPath = import_path13.default.join(dir, ".git");
|
|
5849
|
+
if (import_fs10.default.existsSync(gitPath) && import_fs10.default.lstatSync(gitPath).isDirectory()) {
|
|
5391
5850
|
cache.set(dir, dir);
|
|
5392
5851
|
return dir;
|
|
5393
5852
|
}
|
|
5394
|
-
const parentDir =
|
|
5853
|
+
const parentDir = import_path13.default.dirname(dir);
|
|
5395
5854
|
if (dir === parentDir) {
|
|
5396
5855
|
cache.set(dir, null);
|
|
5397
5856
|
return null;
|
|
@@ -5435,8 +5894,8 @@ function applyPatchWithConflictMarkers(oldText, newText) {
|
|
|
5435
5894
|
}
|
|
5436
5895
|
|
|
5437
5896
|
// packages/playwright/src/runner/workerHost.ts
|
|
5438
|
-
var
|
|
5439
|
-
var
|
|
5897
|
+
var import_fs11 = __toESM(require("fs"));
|
|
5898
|
+
var import_path14 = __toESM(require("path"));
|
|
5440
5899
|
var import_common6 = require("../common");
|
|
5441
5900
|
|
|
5442
5901
|
// packages/playwright/src/isomorphic/folders.ts
|
|
@@ -5465,13 +5924,13 @@ var WorkerHost = class extends ProcessHost {
|
|
|
5465
5924
|
repeatEachIndex: testGroup.repeatEachIndex,
|
|
5466
5925
|
projectId: testGroup.projectId,
|
|
5467
5926
|
config: options.config,
|
|
5468
|
-
artifactsDir:
|
|
5927
|
+
artifactsDir: import_path14.default.join(options.outputDir, artifactsFolderName(workerIndex)),
|
|
5469
5928
|
pauseOnError: options.pauseOnError,
|
|
5470
5929
|
pauseAtEnd: options.pauseAtEnd
|
|
5471
5930
|
};
|
|
5472
5931
|
}
|
|
5473
5932
|
async start() {
|
|
5474
|
-
await
|
|
5933
|
+
await import_fs11.default.promises.mkdir(this._params.artifactsDir, { recursive: true });
|
|
5475
5934
|
return await this.startRunner(this._params, {
|
|
5476
5935
|
onStdOut: (chunk) => this.emit("stdOut", import_common6.ipc.stdioChunkToParams(chunk)),
|
|
5477
5936
|
onStdErr: (chunk) => this.emit("stdErr", import_common6.ipc.stdioChunkToParams(chunk))
|
|
@@ -5507,7 +5966,7 @@ var WorkerHost = class extends ProcessHost {
|
|
|
5507
5966
|
|
|
5508
5967
|
// packages/playwright/src/runner/dispatcher.ts
|
|
5509
5968
|
var import_common7 = require("../common");
|
|
5510
|
-
var
|
|
5969
|
+
var import_util12 = require("../util");
|
|
5511
5970
|
var colors4 = require("playwright-core/lib/utilsBundle").colors;
|
|
5512
5971
|
var { ManualPromise: ManualPromise3 } = require("playwright-core/lib/coreBundle").iso;
|
|
5513
5972
|
var { eventsHelper } = require("playwright-core/lib/coreBundle").utils;
|
|
@@ -5530,11 +5989,22 @@ var Dispatcher = class {
|
|
|
5530
5989
|
this._workerLimitPerProjectId.set(project.id, project.workers);
|
|
5531
5990
|
}
|
|
5532
5991
|
}
|
|
5992
|
+
_heldLocks() {
|
|
5993
|
+
const heldLocks = /* @__PURE__ */ new Set();
|
|
5994
|
+
for (const slot of this._workerSlots) {
|
|
5995
|
+
for (const lock of slot.jobDispatcher?.job.locks || [])
|
|
5996
|
+
heldLocks.add(lock);
|
|
5997
|
+
}
|
|
5998
|
+
return heldLocks;
|
|
5999
|
+
}
|
|
5533
6000
|
_findFirstJobToRun() {
|
|
6001
|
+
const heldLocks = this._heldLocks();
|
|
5534
6002
|
for (let index = 0; index < this._queue.length; index++) {
|
|
5535
6003
|
const job = this._queue[index];
|
|
5536
6004
|
if (this._isolatedJobs.has(job) && this._workerSlots.some((w) => !!w.jobDispatcher))
|
|
5537
6005
|
continue;
|
|
6006
|
+
if (job.locks.some((lock) => heldLocks.has(lock)))
|
|
6007
|
+
continue;
|
|
5538
6008
|
const projectIdWorkerLimit = this._workerLimitPerProjectId.get(job.projectId);
|
|
5539
6009
|
if (!projectIdWorkerLimit)
|
|
5540
6010
|
return index;
|
|
@@ -5544,18 +6014,22 @@ var Dispatcher = class {
|
|
|
5544
6014
|
}
|
|
5545
6015
|
return -1;
|
|
5546
6016
|
}
|
|
6017
|
+
_scheduleJobs() {
|
|
6018
|
+
while (this._scheduleJob()) {
|
|
6019
|
+
}
|
|
6020
|
+
}
|
|
5547
6021
|
_scheduleJob() {
|
|
5548
|
-
if (this._isStopped)
|
|
5549
|
-
return;
|
|
6022
|
+
if (this._isStopped || !this._workerSlots.some((w) => !w.jobDispatcher))
|
|
6023
|
+
return false;
|
|
5550
6024
|
const jobIndex = this._findFirstJobToRun();
|
|
5551
6025
|
if (jobIndex === -1)
|
|
5552
|
-
return;
|
|
6026
|
+
return false;
|
|
5553
6027
|
const job = this._queue[jobIndex];
|
|
5554
6028
|
let workerIndex = this._workerSlots.findIndex((w) => !w.jobDispatcher && w.worker && w.worker.hash() === job.workerHash && !w.worker.didSendStop());
|
|
5555
6029
|
if (workerIndex === -1)
|
|
5556
6030
|
workerIndex = this._workerSlots.findIndex((w) => !w.jobDispatcher);
|
|
5557
6031
|
if (workerIndex === -1) {
|
|
5558
|
-
return;
|
|
6032
|
+
return false;
|
|
5559
6033
|
}
|
|
5560
6034
|
this._queue.splice(jobIndex, 1);
|
|
5561
6035
|
const jobDispatcher = new JobDispatcher(job, this._testRun, this._ignoreMaxFailures ? void 0 : () => this.stop().catch(() => {
|
|
@@ -5564,8 +6038,9 @@ var Dispatcher = class {
|
|
|
5564
6038
|
void this._runJobInWorker(workerIndex, jobDispatcher).then(() => {
|
|
5565
6039
|
this._workerSlots[workerIndex].jobDispatcher = void 0;
|
|
5566
6040
|
this._checkFinished();
|
|
5567
|
-
this.
|
|
6041
|
+
this._scheduleJobs();
|
|
5568
6042
|
});
|
|
6043
|
+
return true;
|
|
5569
6044
|
}
|
|
5570
6045
|
async _runJobInWorker(index, jobDispatcher) {
|
|
5571
6046
|
const job = jobDispatcher.job;
|
|
@@ -5643,8 +6118,7 @@ var Dispatcher = class {
|
|
|
5643
6118
|
void this.stop();
|
|
5644
6119
|
for (let i = 0; i < this._testRun.config.config.workers; i++)
|
|
5645
6120
|
this._workerSlots.push({});
|
|
5646
|
-
|
|
5647
|
-
this._scheduleJob();
|
|
6121
|
+
this._scheduleJobs();
|
|
5648
6122
|
this._checkFinished();
|
|
5649
6123
|
await this._finished;
|
|
5650
6124
|
}
|
|
@@ -5786,19 +6260,23 @@ var JobDispatcher = class {
|
|
|
5786
6260
|
const parentStep = params.parentStepId ? steps.get(params.parentStepId) : void 0;
|
|
5787
6261
|
const step = {
|
|
5788
6262
|
title: params.title,
|
|
6263
|
+
subtitle: params.subtitle,
|
|
5789
6264
|
titlePath: () => {
|
|
5790
6265
|
const parentPath = parentStep?.titlePath() || [];
|
|
5791
6266
|
return [...parentPath, params.title];
|
|
5792
6267
|
},
|
|
5793
6268
|
parent: parentStep,
|
|
5794
6269
|
category: params.category,
|
|
6270
|
+
params: params.params,
|
|
5795
6271
|
startTime: new Date(params.wallTime),
|
|
5796
6272
|
duration: -1,
|
|
5797
6273
|
steps: [],
|
|
5798
6274
|
attachments: [],
|
|
5799
6275
|
annotations: [],
|
|
5800
6276
|
location: params.location,
|
|
5801
|
-
_stepId: params.stepId
|
|
6277
|
+
_stepId: params.stepId,
|
|
6278
|
+
_apiName: params.apiName,
|
|
6279
|
+
_channelMethod: params.channelMethod
|
|
5802
6280
|
};
|
|
5803
6281
|
steps.set(params.stepId, step);
|
|
5804
6282
|
(parentStep || result).steps.push(step);
|
|
@@ -5980,7 +6458,7 @@ var JobDispatcher = class {
|
|
|
5980
6458
|
addLocationAndSnippetToError(this._testRun.config.config, response.error);
|
|
5981
6459
|
return response;
|
|
5982
6460
|
} catch (e) {
|
|
5983
|
-
const error = (0,
|
|
6461
|
+
const error = (0, import_util12.serializeError)(e);
|
|
5984
6462
|
addLocationAndSnippetToError(this._testRun.config.config, error);
|
|
5985
6463
|
return { response: void 0, error };
|
|
5986
6464
|
}
|
|
@@ -6099,7 +6577,7 @@ var FixedNodeSIGINTHandler = class {
|
|
|
6099
6577
|
};
|
|
6100
6578
|
|
|
6101
6579
|
// packages/playwright/src/runner/taskRunner.ts
|
|
6102
|
-
var
|
|
6580
|
+
var import_util13 = require("../util");
|
|
6103
6581
|
var colors5 = require("playwright-core/lib/utilsBundle").colors;
|
|
6104
6582
|
var debug4 = require("playwright-core/lib/utilsBundle").debug;
|
|
6105
6583
|
var { ManualPromise: ManualPromise4 } = require("playwright-core/lib/coreBundle").iso;
|
|
@@ -6140,7 +6618,7 @@ var TaskRunner = class _TaskRunner {
|
|
|
6140
6618
|
await task.setup?.(context, errors, softErrors);
|
|
6141
6619
|
} catch (e) {
|
|
6142
6620
|
debug4("pw:test:task")(`error in "${task.title}": `, e);
|
|
6143
|
-
errors.push((0,
|
|
6621
|
+
errors.push((0, import_util13.serializeError)(e));
|
|
6144
6622
|
} finally {
|
|
6145
6623
|
for (const error of [...softErrors, ...errors])
|
|
6146
6624
|
this._reporter.onError?.(error);
|
|
@@ -6202,7 +6680,7 @@ var TimeoutWatcher = class {
|
|
|
6202
6680
|
|
|
6203
6681
|
// packages/playwright/src/runner/vcs.ts
|
|
6204
6682
|
var import_child_process2 = __toESM(require("child_process"));
|
|
6205
|
-
var
|
|
6683
|
+
var import_path15 = __toESM(require("path"));
|
|
6206
6684
|
var import_common8 = require("../common");
|
|
6207
6685
|
async function detectChangedTestFiles(baseCommit, configDir) {
|
|
6208
6686
|
function gitFileList(args) {
|
|
@@ -6232,20 +6710,20 @@ async function detectChangedTestFiles(baseCommit, configDir) {
|
|
|
6232
6710
|
].join("\n"));
|
|
6233
6711
|
}
|
|
6234
6712
|
}
|
|
6235
|
-
const untrackedFiles = gitFileList(["ls-files", "--others", "--exclude-standard"]).map((file) =>
|
|
6713
|
+
const untrackedFiles = gitFileList(["ls-files", "--others", "--exclude-standard"]).map((file) => import_path15.default.join(configDir, file));
|
|
6236
6714
|
const [gitRoot] = gitFileList(["rev-parse", "--show-toplevel"]);
|
|
6237
|
-
const trackedFilesWithChanges = gitFileList(["diff", baseCommit, "--name-only"]).map((file) =>
|
|
6715
|
+
const trackedFilesWithChanges = gitFileList(["diff", baseCommit, "--name-only"]).map((file) => import_path15.default.join(gitRoot, file));
|
|
6238
6716
|
return new Set(import_common8.cc.affectedTestFiles([...untrackedFiles, ...trackedFilesWithChanges]));
|
|
6239
6717
|
}
|
|
6240
6718
|
|
|
6241
6719
|
// packages/playwright/src/runner/tasks.ts
|
|
6242
6720
|
var import_common9 = require("../common");
|
|
6243
|
-
var
|
|
6721
|
+
var import_util15 = require("../util");
|
|
6244
6722
|
var debug5 = require("playwright-core/lib/utilsBundle").debug;
|
|
6245
6723
|
var { ManualPromise: ManualPromise5 } = require("playwright-core/lib/coreBundle").iso;
|
|
6246
6724
|
var { monotonicTime: monotonicTime6 } = require("playwright-core/lib/coreBundle").iso;
|
|
6247
6725
|
var { removeFolders: removeFolders4 } = require("playwright-core/lib/coreBundle").utils;
|
|
6248
|
-
var readDirAsync2 = (0,
|
|
6726
|
+
var readDirAsync2 = (0, import_util14.promisify)(import_fs12.default.readdir);
|
|
6249
6727
|
var TestRun = class {
|
|
6250
6728
|
constructor(config2, reporter, options) {
|
|
6251
6729
|
this.rootSuite = void 0;
|
|
@@ -6316,7 +6794,6 @@ function createRunTestsTasks(config2) {
|
|
|
6316
6794
|
return [
|
|
6317
6795
|
createPhasesTask(),
|
|
6318
6796
|
createReportBeginTask(),
|
|
6319
|
-
...config2.plugins.map((plugin) => createPluginBeginTask(plugin)),
|
|
6320
6797
|
createRunTestsTask()
|
|
6321
6798
|
];
|
|
6322
6799
|
}
|
|
@@ -6324,9 +6801,7 @@ function createClearCacheTask(config2) {
|
|
|
6324
6801
|
return {
|
|
6325
6802
|
title: "clear cache",
|
|
6326
6803
|
setup: async () => {
|
|
6327
|
-
await (0,
|
|
6328
|
-
for (const plugin of config2.plugins)
|
|
6329
|
-
await plugin.instance?.clearCache?.();
|
|
6804
|
+
await (0, import_util15.removeDirAndLogToConsole)(import_common9.cc.cacheDir);
|
|
6330
6805
|
}
|
|
6331
6806
|
};
|
|
6332
6807
|
}
|
|
@@ -6355,17 +6830,6 @@ function createPluginSetupTasks(config2) {
|
|
|
6355
6830
|
}
|
|
6356
6831
|
}));
|
|
6357
6832
|
}
|
|
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
6833
|
function createGlobalSetupTask(file, config2) {
|
|
6370
6834
|
let title = "global setup";
|
|
6371
6835
|
if (config2.globalSetups.length > 1)
|
|
@@ -6408,7 +6872,7 @@ function createRemoveOutputDirsTask() {
|
|
|
6408
6872
|
return;
|
|
6409
6873
|
if (error.code === "EBUSY") {
|
|
6410
6874
|
const entries = await readDirAsync2(outputDir).catch((e) => []);
|
|
6411
|
-
await Promise.all(entries.map((entry) => removeFolders4([
|
|
6875
|
+
await Promise.all(entries.map((entry) => removeFolders4([import_path16.default.join(outputDir, entry)])));
|
|
6412
6876
|
} else {
|
|
6413
6877
|
throw error;
|
|
6414
6878
|
}
|
|
@@ -6427,7 +6891,7 @@ function createListFilesTask() {
|
|
|
6427
6891
|
projectSuite._fullProject = project;
|
|
6428
6892
|
testRun.rootSuite._addSuite(projectSuite);
|
|
6429
6893
|
const suites = files.map((file) => {
|
|
6430
|
-
const title =
|
|
6894
|
+
const title = import_path16.default.relative(testRun.config.config.rootDir, file);
|
|
6431
6895
|
const suite = new import_common9.test.Suite(title, "file");
|
|
6432
6896
|
suite.location = { file, line: 0, column: 0 };
|
|
6433
6897
|
projectSuite._addSuite(suite);
|
|
@@ -6457,8 +6921,8 @@ function createLoadTask(mode, options) {
|
|
|
6457
6921
|
testRun.preOnlyTestFilters.push((test) => !testFilter(test));
|
|
6458
6922
|
}
|
|
6459
6923
|
if (testRun.options.grep || testRun.options.grepInvert) {
|
|
6460
|
-
const grepMatcher = testRun.options.grep ? (0,
|
|
6461
|
-
const grepInvertMatcher = testRun.options.grepInvert ? (0,
|
|
6924
|
+
const grepMatcher = testRun.options.grep ? (0, import_util15.createTitleMatcher)((0, import_util15.forceRegExp)(testRun.options.grep)) : () => true;
|
|
6925
|
+
const grepInvertMatcher = testRun.options.grepInvert ? (0, import_util15.createTitleMatcher)((0, import_util15.forceRegExp)(testRun.options.grepInvert)) : () => false;
|
|
6462
6926
|
testRun.preOnlyTestFilters.push((test) => {
|
|
6463
6927
|
const grepTitle = test._grepTitleWithTags();
|
|
6464
6928
|
return !grepInvertMatcher(grepTitle) && grepMatcher(grepTitle);
|
|
@@ -6470,10 +6934,6 @@ function createLoadTask(mode, options) {
|
|
|
6470
6934
|
}
|
|
6471
6935
|
await collectProjectsAndTestFiles(testRun, !!options.doNotRunDepsOutsideProjectFilter);
|
|
6472
6936
|
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
6937
|
if (testRun.options.onlyChanged) {
|
|
6478
6938
|
const changedFiles = await detectChangedTestFiles(testRun.options.onlyChanged, testRun.config.configDir);
|
|
6479
6939
|
testRun.preOnlyTestFilters.push((test) => changedFiles.has(test.location.file));
|
|
@@ -6597,25 +7057,32 @@ function createRunTestsTask() {
|
|
|
6597
7057
|
}
|
|
6598
7058
|
|
|
6599
7059
|
// packages/playwright/src/runner/lastRun.ts
|
|
6600
|
-
var
|
|
6601
|
-
var
|
|
7060
|
+
var import_fs13 = __toESM(require("fs"));
|
|
7061
|
+
var import_path17 = __toESM(require("path"));
|
|
7062
|
+
function didNotRun(test) {
|
|
7063
|
+
if (test.outcome() !== "skipped")
|
|
7064
|
+
return false;
|
|
7065
|
+
if (test.results.some((result) => result.status === "interrupted"))
|
|
7066
|
+
return false;
|
|
7067
|
+
return !test.results.length || test.expectedStatus !== "skipped";
|
|
7068
|
+
}
|
|
6602
7069
|
var LastRunReporter = class {
|
|
6603
7070
|
constructor(filteredProjects, listMode, lastFailedFileOverride) {
|
|
6604
7071
|
this._listMode = !!listMode;
|
|
6605
7072
|
const override = lastFailedFileOverride ?? process.env.PLAYWRIGHT_LAST_RUN_OUTPUT_FILE;
|
|
6606
7073
|
if (override) {
|
|
6607
|
-
this._lastRunFile =
|
|
7074
|
+
this._lastRunFile = import_path17.default.resolve(process.cwd(), override);
|
|
6608
7075
|
} else {
|
|
6609
7076
|
const [project] = filteredProjects;
|
|
6610
7077
|
if (project)
|
|
6611
|
-
this._lastRunFile =
|
|
7078
|
+
this._lastRunFile = import_path17.default.join(project.project.outputDir, ".last-run.json");
|
|
6612
7079
|
}
|
|
6613
7080
|
}
|
|
6614
7081
|
async filterLastFailed() {
|
|
6615
7082
|
if (!this._lastRunFile)
|
|
6616
7083
|
return void 0;
|
|
6617
7084
|
try {
|
|
6618
|
-
const lastRunInfo = JSON.parse(await
|
|
7085
|
+
const lastRunInfo = JSON.parse(await import_fs13.default.promises.readFile(this._lastRunFile, "utf8"));
|
|
6619
7086
|
return lastRunInfo.failedTests;
|
|
6620
7087
|
} catch {
|
|
6621
7088
|
return void 0;
|
|
@@ -6635,10 +7102,10 @@ var LastRunReporter = class {
|
|
|
6635
7102
|
return;
|
|
6636
7103
|
const lastRunInfo = {
|
|
6637
7104
|
status: result.status,
|
|
6638
|
-
failedTests: this._suite?.allTests().filter((t2) => !t2.ok()).map((t2) => t2.id) || []
|
|
7105
|
+
failedTests: this._suite?.allTests().filter((t2) => !t2.ok() || didNotRun(t2)).map((t2) => t2.id) || []
|
|
6639
7106
|
};
|
|
6640
|
-
await
|
|
6641
|
-
await
|
|
7107
|
+
await import_fs13.default.promises.mkdir(import_path17.default.dirname(this._lastRunFile), { recursive: true });
|
|
7108
|
+
await import_fs13.default.promises.writeFile(this._lastRunFile, JSON.stringify(lastRunInfo, void 0, 2));
|
|
6642
7109
|
}
|
|
6643
7110
|
};
|
|
6644
7111
|
|
|
@@ -6658,7 +7125,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6658
7125
|
this._watchedTestDependencies = /* @__PURE__ */ new Set();
|
|
6659
7126
|
this._queue = Promise.resolve();
|
|
6660
7127
|
this._watchTestDirs = false;
|
|
6661
|
-
this._populateDependenciesOnList = false;
|
|
6662
7128
|
this._startingEnv = {};
|
|
6663
7129
|
this.configLocation = configLocation;
|
|
6664
7130
|
this._configCLIOverrides = configCLIOverrides;
|
|
@@ -6671,7 +7137,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6671
7137
|
async initialize(params) {
|
|
6672
7138
|
setPlaywrightTestProcessEnv();
|
|
6673
7139
|
this._watchTestDirs = !!params.watchTestDirs;
|
|
6674
|
-
this._populateDependenciesOnList = !!params.populateDependenciesOnList;
|
|
6675
7140
|
this._startingEnv = { ...process.env };
|
|
6676
7141
|
}
|
|
6677
7142
|
resizeTerminal(params) {
|
|
@@ -6683,7 +7148,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6683
7148
|
hasSomeBrowsers() {
|
|
6684
7149
|
for (const browserName of ["chromium", "webkit", "firefox"]) {
|
|
6685
7150
|
try {
|
|
6686
|
-
|
|
7151
|
+
import_coreBundle3.registry.registry.findExecutable(browserName).executablePathOrDie("javascript");
|
|
6687
7152
|
return true;
|
|
6688
7153
|
} catch {
|
|
6689
7154
|
}
|
|
@@ -6691,8 +7156,8 @@ var TestRunner = class extends import_events2.default {
|
|
|
6691
7156
|
return false;
|
|
6692
7157
|
}
|
|
6693
7158
|
async installBrowsers() {
|
|
6694
|
-
const executables =
|
|
6695
|
-
await
|
|
7159
|
+
const executables = import_coreBundle3.registry.registry.defaultExecutables();
|
|
7160
|
+
await import_coreBundle3.registry.registry.install(executables);
|
|
6696
7161
|
}
|
|
6697
7162
|
async loadConfig() {
|
|
6698
7163
|
const { config: config2, error } = await this._loadConfig(this._configCLIOverrides);
|
|
@@ -6732,7 +7197,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6732
7197
|
if (!config2)
|
|
6733
7198
|
return { status: "failed" };
|
|
6734
7199
|
const status = await runTasks(new TestRun(config2, reporter), [
|
|
6735
|
-
...createPluginSetupTasks(config2),
|
|
6736
7200
|
createClearCacheTask(config2)
|
|
6737
7201
|
]);
|
|
6738
7202
|
return { status };
|
|
@@ -6779,7 +7243,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6779
7243
|
listMode: true
|
|
6780
7244
|
};
|
|
6781
7245
|
const status = await runTasks(new TestRun(config2, reporter, options), [
|
|
6782
|
-
createLoadTask("out-of-process", { failOnLoadErrors: false, filterOnly: false
|
|
7246
|
+
createLoadTask("out-of-process", { failOnLoadErrors: false, filterOnly: false }),
|
|
6783
7247
|
createReportBeginTask()
|
|
6784
7248
|
]);
|
|
6785
7249
|
return { config: config2, status };
|
|
@@ -6791,11 +7255,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6791
7255
|
this._watchedProjectDirs.add(p.project.testDir);
|
|
6792
7256
|
this._ignoredProjectOutputs.add(p.project.outputDir);
|
|
6793
7257
|
}
|
|
6794
|
-
const result = await resolveCtDirs(config2);
|
|
6795
|
-
if (result) {
|
|
6796
|
-
this._watchedProjectDirs.add(result.templateDir);
|
|
6797
|
-
this._ignoredProjectOutputs.add(result.outDir);
|
|
6798
|
-
}
|
|
6799
7258
|
if (this._watchTestDirs)
|
|
6800
7259
|
await this._updateWatcher(false);
|
|
6801
7260
|
}
|
|
@@ -6886,7 +7345,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6886
7345
|
return { errors: errorReporter.errors(), testFiles: [] };
|
|
6887
7346
|
const status = await runTasks(new TestRun(config2, reporter), [
|
|
6888
7347
|
...createPluginSetupTasks(config2),
|
|
6889
|
-
createLoadTask("out-of-process", { failOnLoadErrors: true, filterOnly: false
|
|
7348
|
+
createLoadTask("out-of-process", { failOnLoadErrors: true, filterOnly: false })
|
|
6890
7349
|
]);
|
|
6891
7350
|
if (status !== "passed")
|
|
6892
7351
|
return { errors: errorReporter.errors(), testFiles: [] };
|
|
@@ -6915,7 +7374,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6915
7374
|
this._lastLoadedConfig = config2;
|
|
6916
7375
|
return { config: config2 };
|
|
6917
7376
|
} catch (e) {
|
|
6918
|
-
return { config: null, error: (0,
|
|
7377
|
+
return { config: null, error: (0, import_util16.serializeError)(e) };
|
|
6919
7378
|
}
|
|
6920
7379
|
}
|
|
6921
7380
|
lastLoadedConfig() {
|
|
@@ -6935,18 +7394,6 @@ var TestRunner = class extends import_events2.default {
|
|
|
6935
7394
|
function printInternalError(e) {
|
|
6936
7395
|
console.error("Internal error:", e);
|
|
6937
7396
|
}
|
|
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
7397
|
async function runAllTestsWithConfig(config2, options) {
|
|
6951
7398
|
setPlaywrightTestProcessEnv();
|
|
6952
7399
|
addGitCommitInfoPlugin(config2);
|
|
@@ -6983,8 +7430,8 @@ __export(testServer_exports, {
|
|
|
6983
7430
|
runTestServer: () => runTestServer,
|
|
6984
7431
|
runUIMode: () => runUIMode
|
|
6985
7432
|
});
|
|
6986
|
-
var
|
|
6987
|
-
var
|
|
7433
|
+
var import_util17 = __toESM(require("util"));
|
|
7434
|
+
var import_coreBundle4 = require("playwright-core/lib/coreBundle");
|
|
6988
7435
|
var import_common11 = require("../common");
|
|
6989
7436
|
|
|
6990
7437
|
// packages/playwright/src/runner/uiModeReporter.ts
|
|
@@ -7013,7 +7460,7 @@ var TestServer = class {
|
|
|
7013
7460
|
}
|
|
7014
7461
|
async start(options) {
|
|
7015
7462
|
this._dispatcher = new TestServerDispatcher(this._configLocation, this._configCLIOverrides);
|
|
7016
|
-
return await
|
|
7463
|
+
return await import_coreBundle4.server.startTraceViewerServer({
|
|
7017
7464
|
host: options.host,
|
|
7018
7465
|
port: options.port,
|
|
7019
7466
|
allowedFileRoots: () => this._allowedFileRoots(),
|
|
@@ -7143,7 +7590,7 @@ var TestServerDispatcher = class {
|
|
|
7143
7590
|
if (interceptStdio) {
|
|
7144
7591
|
if (debug6.log === originalDebugLog) {
|
|
7145
7592
|
debug6.log = (...args) => {
|
|
7146
|
-
const string =
|
|
7593
|
+
const string = import_util17.default.format(...args) + "\n";
|
|
7147
7594
|
return originalStderrWrite.apply(process.stderr, [string]);
|
|
7148
7595
|
};
|
|
7149
7596
|
}
|
|
@@ -7169,12 +7616,12 @@ var TestServerDispatcher = class {
|
|
|
7169
7616
|
async function runUIMode(configFile, configCLIOverrides, options) {
|
|
7170
7617
|
const configLocation = import_common11.configLoader.resolveConfigLocation(configFile);
|
|
7171
7618
|
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server, cancelPromise) => {
|
|
7172
|
-
await
|
|
7619
|
+
await import_coreBundle4.server.installRootRedirect(server, void 0, { ...options, webApp: "uiMode.html" });
|
|
7173
7620
|
if (options.host !== void 0 || options.port !== void 0) {
|
|
7174
|
-
await
|
|
7621
|
+
await import_coreBundle4.server.openTraceInBrowser(server.urlPrefix("human-readable"));
|
|
7175
7622
|
} else {
|
|
7176
7623
|
const channel = await installedChromiumChannelForUI(configLocation, configCLIOverrides);
|
|
7177
|
-
const page = await
|
|
7624
|
+
const page = await import_coreBundle4.server.openTraceViewerApp(server.urlPrefix("precise"), "chromium", {
|
|
7178
7625
|
headless: isUnderTest() && process.env.PWTEST_HEADED_FOR_TEST !== "1",
|
|
7179
7626
|
persistentContextOptions: {
|
|
7180
7627
|
handleSIGINT: false,
|
|
@@ -7239,7 +7686,7 @@ __export(watchMode_exports, {
|
|
|
7239
7686
|
var import_path18 = __toESM(require("path"));
|
|
7240
7687
|
var import_readline = __toESM(require("readline"));
|
|
7241
7688
|
var import_events3 = require("events");
|
|
7242
|
-
var
|
|
7689
|
+
var import_coreBundle5 = require("playwright-core/lib/coreBundle");
|
|
7243
7690
|
|
|
7244
7691
|
// packages/playwright/src/isomorphic/testTree.ts
|
|
7245
7692
|
var statusEx = /* @__PURE__ */ Symbol("statusEx");
|
|
@@ -7658,8 +8105,7 @@ async function runWatchModeLoop(configLocation, initialOptions) {
|
|
|
7658
8105
|
testServerConnection.onReport((report2) => teleSuiteUpdater.processTestReportEvent(report2));
|
|
7659
8106
|
await testServerConnection.initialize({
|
|
7660
8107
|
interceptStdio: false,
|
|
7661
|
-
watchTestDirs: true
|
|
7662
|
-
populateDependenciesOnList: true
|
|
8108
|
+
watchTestDirs: true
|
|
7663
8109
|
});
|
|
7664
8110
|
await testServerConnection.runGlobalSetup({});
|
|
7665
8111
|
const { report } = await testServerConnection.listTests({});
|
|
@@ -7921,7 +8367,7 @@ ${colors6.dim("Waiting for file changes. Press")} ${colors6.bold("enter")} ${col
|
|
|
7921
8367
|
}
|
|
7922
8368
|
async function toggleShowBrowser() {
|
|
7923
8369
|
if (!showBrowserServer) {
|
|
7924
|
-
showBrowserServer = new
|
|
8370
|
+
showBrowserServer = new import_coreBundle5.remote.PlaywrightServer({ mode: "extension", path: "/" + createGuid3(), maxConnections: 1 });
|
|
7925
8371
|
connectWsEndpoint = await showBrowserServer.listen();
|
|
7926
8372
|
process.stdout.write(`${colors6.dim("Show & reuse browser:")} ${colors6.bold("on")}
|
|
7927
8373
|
`);
|
|
@@ -7985,7 +8431,7 @@ var JsonStringInternalizer = class {
|
|
|
7985
8431
|
};
|
|
7986
8432
|
|
|
7987
8433
|
// packages/playwright/src/reporters/merge.ts
|
|
7988
|
-
var
|
|
8434
|
+
var import_util18 = require("../util");
|
|
7989
8435
|
var { isPathInside } = require("playwright-core/lib/coreBundle").utils;
|
|
7990
8436
|
var { ZipFile } = require("playwright-core/lib/coreBundle").utils;
|
|
7991
8437
|
async function createMergedReport(config2, dir, reporterDescriptions, rootDirOverride) {
|
|
@@ -8081,7 +8527,7 @@ async function extractAndParseReports(dir, shardFiles, internalizer, printStatus
|
|
|
8081
8527
|
const reportNames = new UniqueFileNameGenerator();
|
|
8082
8528
|
for (const file of shardFiles) {
|
|
8083
8529
|
const absolutePath = import_path19.default.join(dir, file);
|
|
8084
|
-
printStatus(`extracting: ${(0,
|
|
8530
|
+
printStatus(`extracting: ${(0, import_util18.relativeFilePath)(absolutePath)}`);
|
|
8085
8531
|
const zipFile = new ZipFile(absolutePath);
|
|
8086
8532
|
const entryNames = await zipFile.entries();
|
|
8087
8533
|
for (const entryName of entryNames.sort()) {
|