@smoothdeploy/playwright 1.61.0 → 1.62.1-beta-1790342324000
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/agents/copilot-setup-steps.yml +2 -2
- package/lib/cli/reportActions.js +2 -2
- package/lib/common/index.js +74 -51
- package/lib/common/index.js.txt +10 -11
- package/lib/errorContext.js +2 -3
- package/lib/index.js +31 -8
- package/lib/matchers/expect.js +4814 -4380
- package/lib/matchers/expect.js.LICENSE +87 -140
- package/lib/matchers/expect.js.txt +30 -35
- package/lib/program.js +19 -0
- package/lib/runner/index.js +615 -299
- package/lib/runner/index.js.txt +15 -13
- package/lib/transform/babelBundle.js +12899 -11654
- package/lib/transform/babelBundle.js.LICENSE +379 -354
- package/lib/transform/babelBundle.js.txt +39 -39
- package/lib/transform/esmLoader.js +3126 -1115
- package/lib/transform/esmLoader.js.LICENSE +81 -61
- package/lib/transform/esmLoader.js.txt +21 -18
- package/lib/util.js +2 -29
- package/lib/worker/workerProcessEntry.js +17 -33
- package/lib/worker/workerProcessEntry.js.txt +7 -8
- package/package.json +3 -6
- package/types/test.d.ts +391 -4
- package/types/testReporter.d.ts +79 -4
package/lib/runner/index.js
CHANGED
|
@@ -56,7 +56,7 @@ var import_events2 = __toESM(require("events"));
|
|
|
56
56
|
var import_fs13 = __toESM(require("fs"));
|
|
57
57
|
var import_path17 = __toESM(require("path"));
|
|
58
58
|
var import_coreBundle2 = require("playwright-core/lib/coreBundle");
|
|
59
|
-
var
|
|
59
|
+
var import_common10 = require("../common");
|
|
60
60
|
|
|
61
61
|
// packages/playwright/src/runner/fsWatcher.ts
|
|
62
62
|
var chokidar = require("playwright-core/lib/utilsBundle").chokidar;
|
|
@@ -432,6 +432,18 @@ var TeleSuite = class {
|
|
|
432
432
|
suite.parent = this;
|
|
433
433
|
this._entries.push(suite);
|
|
434
434
|
}
|
|
435
|
+
skip(_reason) {
|
|
436
|
+
throw new Error("Disposition methods are not supported on a TeleSuite (read-only).");
|
|
437
|
+
}
|
|
438
|
+
fixme(_reason) {
|
|
439
|
+
throw new Error("Disposition methods are not supported on a TeleSuite (read-only).");
|
|
440
|
+
}
|
|
441
|
+
fail(_reason) {
|
|
442
|
+
throw new Error("Disposition methods are not supported on a TeleSuite (read-only).");
|
|
443
|
+
}
|
|
444
|
+
exclude() {
|
|
445
|
+
throw new Error("Disposition methods are not supported on a TeleSuite (read-only).");
|
|
446
|
+
}
|
|
435
447
|
};
|
|
436
448
|
var TeleTestCase = class {
|
|
437
449
|
constructor(id, title, location, repeatEachIndex) {
|
|
@@ -467,6 +479,18 @@ var TeleTestCase = class {
|
|
|
467
479
|
this.results.push(result);
|
|
468
480
|
return result;
|
|
469
481
|
}
|
|
482
|
+
skip(_reason) {
|
|
483
|
+
throw new Error("Disposition methods are not supported on a TeleTestCase (read-only).");
|
|
484
|
+
}
|
|
485
|
+
fixme(_reason) {
|
|
486
|
+
throw new Error("Disposition methods are not supported on a TeleTestCase (read-only).");
|
|
487
|
+
}
|
|
488
|
+
fail(_reason) {
|
|
489
|
+
throw new Error("Disposition methods are not supported on a TeleTestCase (read-only).");
|
|
490
|
+
}
|
|
491
|
+
exclude() {
|
|
492
|
+
throw new Error("Disposition methods are not supported on a TeleTestCase (read-only).");
|
|
493
|
+
}
|
|
470
494
|
};
|
|
471
495
|
var TeleTestStep = class {
|
|
472
496
|
constructor(payload, parentStep, location, result) {
|
|
@@ -1011,10 +1035,10 @@ var import_util2 = require("../util");
|
|
|
1011
1035
|
var realColors = require("playwright-core/lib/utilsBundle").colors;
|
|
1012
1036
|
var { noColors } = require("playwright-core/lib/coreBundle").iso;
|
|
1013
1037
|
var { msToString } = require("playwright-core/lib/coreBundle").iso;
|
|
1014
|
-
var { parseErrorStack } = require("playwright-core/lib/coreBundle").
|
|
1038
|
+
var { parseErrorStack } = require("playwright-core/lib/coreBundle").utils;
|
|
1015
1039
|
var { getPackageManagerExecCommand } = require("playwright-core/lib/coreBundle").utils;
|
|
1016
1040
|
var { fitToWidth } = require("playwright-core/lib/coreBundle").utils;
|
|
1017
|
-
var kOutputSymbol = Symbol("output");
|
|
1041
|
+
var kOutputSymbol = /* @__PURE__ */ Symbol("output");
|
|
1018
1042
|
var DEFAULT_TTY_WIDTH = 100;
|
|
1019
1043
|
var DEFAULT_TTY_HEIGHT = 40;
|
|
1020
1044
|
var originalProcessStdout = process.stdout;
|
|
@@ -1024,8 +1048,9 @@ var StripAnsiStream = class extends import_stream.Writable {
|
|
|
1024
1048
|
super();
|
|
1025
1049
|
this._target = target;
|
|
1026
1050
|
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1051
|
+
write(chunk, encodingOrCallback, callback) {
|
|
1052
|
+
const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
|
|
1053
|
+
return this._target.write((0, import_util2.stripAnsiEscapes)(chunk.toString()), cb);
|
|
1029
1054
|
}
|
|
1030
1055
|
};
|
|
1031
1056
|
var terminalScreen = (() => {
|
|
@@ -1373,7 +1398,7 @@ function quotePathIfNeeded(path21) {
|
|
|
1373
1398
|
return `"${path21}"`;
|
|
1374
1399
|
return path21;
|
|
1375
1400
|
}
|
|
1376
|
-
var kReportedSymbol = Symbol("reported");
|
|
1401
|
+
var kReportedSymbol = /* @__PURE__ */ Symbol("reported");
|
|
1377
1402
|
function markErrorsAsReported(result) {
|
|
1378
1403
|
result[kReportedSymbol] = result.errors.length;
|
|
1379
1404
|
}
|
|
@@ -1482,7 +1507,7 @@ function indent(lines, tab) {
|
|
|
1482
1507
|
return lines.replace(/^(?=.+$)/gm, tab);
|
|
1483
1508
|
}
|
|
1484
1509
|
function prepareErrorStack(stack) {
|
|
1485
|
-
return parseErrorStack(stack
|
|
1510
|
+
return parseErrorStack(stack);
|
|
1486
1511
|
}
|
|
1487
1512
|
function resolveFromEnv(name) {
|
|
1488
1513
|
const value = process.env[name];
|
|
@@ -1546,52 +1571,61 @@ function groupAttachments(attachments) {
|
|
|
1546
1571
|
var import_fs = __toESM(require("fs"));
|
|
1547
1572
|
|
|
1548
1573
|
// packages/playwright/src/reporters/multiplexer.ts
|
|
1574
|
+
var import_util3 = require("../util");
|
|
1549
1575
|
var Multiplexer = class {
|
|
1550
1576
|
constructor(reporters) {
|
|
1577
|
+
this._hasReporterErrors = false;
|
|
1551
1578
|
this._reporters = reporters;
|
|
1552
1579
|
}
|
|
1553
1580
|
version() {
|
|
1554
1581
|
return "v2";
|
|
1555
1582
|
}
|
|
1583
|
+
hasReporterErrors() {
|
|
1584
|
+
return this._hasReporterErrors;
|
|
1585
|
+
}
|
|
1556
1586
|
onConfigure(config2) {
|
|
1557
1587
|
for (const reporter of this._reporters)
|
|
1558
|
-
|
|
1588
|
+
this._wrap(() => reporter.onConfigure?.(config2));
|
|
1589
|
+
}
|
|
1590
|
+
async preprocess(params) {
|
|
1591
|
+
for (const reporter of this._reporters)
|
|
1592
|
+
await reporter.preprocess?.(params);
|
|
1559
1593
|
}
|
|
1560
1594
|
onBegin(suite) {
|
|
1561
1595
|
for (const reporter of this._reporters)
|
|
1562
|
-
|
|
1596
|
+
this._wrap(() => reporter.onBegin?.(suite));
|
|
1563
1597
|
}
|
|
1564
1598
|
onTestBegin(test, result) {
|
|
1565
1599
|
for (const reporter of this._reporters)
|
|
1566
|
-
|
|
1600
|
+
this._wrap(() => reporter.onTestBegin?.(test, result));
|
|
1567
1601
|
}
|
|
1568
1602
|
onStdOut(chunk, test, result) {
|
|
1569
1603
|
for (const reporter of this._reporters)
|
|
1570
|
-
|
|
1604
|
+
this._wrap(() => reporter.onStdOut?.(chunk, test, result));
|
|
1571
1605
|
}
|
|
1572
1606
|
onStdErr(chunk, test, result) {
|
|
1573
1607
|
for (const reporter of this._reporters)
|
|
1574
|
-
|
|
1608
|
+
this._wrap(() => reporter.onStdErr?.(chunk, test, result));
|
|
1575
1609
|
}
|
|
1576
1610
|
async onTestPaused(test, result) {
|
|
1577
1611
|
for (const reporter of this._reporters)
|
|
1578
|
-
await
|
|
1612
|
+
await this._wrapAsync(() => reporter.onTestPaused?.(test, result));
|
|
1579
1613
|
}
|
|
1580
1614
|
onTestEnd(test, result) {
|
|
1581
1615
|
for (const reporter of this._reporters)
|
|
1582
|
-
|
|
1616
|
+
this._wrap(() => reporter.onTestEnd?.(test, result));
|
|
1583
1617
|
}
|
|
1584
1618
|
onReportConfigure(params) {
|
|
1585
1619
|
for (const reporter of this._reporters)
|
|
1586
|
-
|
|
1620
|
+
this._wrap(() => reporter.onReportConfigure?.(params));
|
|
1587
1621
|
}
|
|
1588
1622
|
onReportEnd(params) {
|
|
1589
1623
|
for (const reporter of this._reporters)
|
|
1590
|
-
|
|
1624
|
+
this._wrap(() => reporter.onReportEnd?.(params));
|
|
1591
1625
|
}
|
|
1592
1626
|
async onEnd(result) {
|
|
1593
1627
|
for (const reporter of this._reporters) {
|
|
1594
|
-
const outResult = await
|
|
1628
|
+
const outResult = await this._wrapAsync(() => reporter.onEnd?.(result));
|
|
1595
1629
|
if (outResult?.status)
|
|
1596
1630
|
result.status = outResult.status;
|
|
1597
1631
|
}
|
|
@@ -1599,42 +1633,45 @@ var Multiplexer = class {
|
|
|
1599
1633
|
}
|
|
1600
1634
|
async onExit() {
|
|
1601
1635
|
for (const reporter of this._reporters)
|
|
1602
|
-
await
|
|
1636
|
+
await this._wrapAsync(() => reporter.onExit?.());
|
|
1603
1637
|
}
|
|
1604
1638
|
onError(error, workerInfo) {
|
|
1605
1639
|
for (const reporter of this._reporters)
|
|
1606
|
-
|
|
1640
|
+
this._wrap(() => reporter.onError?.(error, workerInfo), false);
|
|
1607
1641
|
}
|
|
1608
1642
|
onStepBegin(test, result, step) {
|
|
1609
1643
|
for (const reporter of this._reporters)
|
|
1610
|
-
|
|
1644
|
+
this._wrap(() => reporter.onStepBegin?.(test, result, step));
|
|
1611
1645
|
}
|
|
1612
1646
|
onStepEnd(test, result, step) {
|
|
1613
1647
|
for (const reporter of this._reporters)
|
|
1614
|
-
|
|
1648
|
+
this._wrap(() => reporter.onStepEnd?.(test, result, step));
|
|
1615
1649
|
}
|
|
1616
1650
|
printsToStdio() {
|
|
1617
1651
|
return this._reporters.some((r) => {
|
|
1618
1652
|
let prints = false;
|
|
1619
|
-
|
|
1653
|
+
this._wrap(() => prints = r.printsToStdio ? r.printsToStdio() : true, false);
|
|
1620
1654
|
return prints;
|
|
1621
1655
|
});
|
|
1622
1656
|
}
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1657
|
+
_wrap(callback, redispatch = true) {
|
|
1658
|
+
try {
|
|
1659
|
+
callback();
|
|
1660
|
+
} catch (e) {
|
|
1661
|
+
this._hasReporterErrors = true;
|
|
1662
|
+
if (redispatch)
|
|
1663
|
+
this.onError((0, import_util3.serializeError)(e));
|
|
1664
|
+
}
|
|
1629
1665
|
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1666
|
+
async _wrapAsync(callback) {
|
|
1667
|
+
try {
|
|
1668
|
+
return await callback();
|
|
1669
|
+
} catch (e) {
|
|
1670
|
+
this._hasReporterErrors = true;
|
|
1671
|
+
this.onError((0, import_util3.serializeError)(e));
|
|
1672
|
+
}
|
|
1636
1673
|
}
|
|
1637
|
-
}
|
|
1674
|
+
};
|
|
1638
1675
|
|
|
1639
1676
|
// packages/playwright/src/reporters/internalReporter.ts
|
|
1640
1677
|
var import_common = require("../common");
|
|
@@ -1660,6 +1697,9 @@ var ReporterV2Wrapper = class {
|
|
|
1660
1697
|
onConfigure(config2) {
|
|
1661
1698
|
this._config = config2;
|
|
1662
1699
|
}
|
|
1700
|
+
preprocess(params) {
|
|
1701
|
+
return this._reporter.preprocess?.(params);
|
|
1702
|
+
}
|
|
1663
1703
|
onBegin(suite) {
|
|
1664
1704
|
this._reporter.onBegin?.(this._config, suite);
|
|
1665
1705
|
const deferred = this._deferred;
|
|
@@ -1727,12 +1767,18 @@ var InternalReporter = class {
|
|
|
1727
1767
|
version() {
|
|
1728
1768
|
return "v2";
|
|
1729
1769
|
}
|
|
1770
|
+
hasReporterErrors() {
|
|
1771
|
+
return this._reporter.hasReporterErrors();
|
|
1772
|
+
}
|
|
1730
1773
|
onConfigure(config2) {
|
|
1731
1774
|
this._config = config2;
|
|
1732
1775
|
this._startTime = /* @__PURE__ */ new Date();
|
|
1733
1776
|
this._monotonicStartTime = monotonicTime3();
|
|
1734
1777
|
this._reporter.onConfigure?.(config2);
|
|
1735
1778
|
}
|
|
1779
|
+
async preprocess(params) {
|
|
1780
|
+
await this._reporter.preprocess(params);
|
|
1781
|
+
}
|
|
1736
1782
|
onBegin(suite) {
|
|
1737
1783
|
this._didBegin = true;
|
|
1738
1784
|
this._reporter.onBegin?.(suite);
|
|
@@ -1779,7 +1825,7 @@ var InternalReporter = class {
|
|
|
1779
1825
|
this._reporter.onStepEnd?.(test, result, step);
|
|
1780
1826
|
}
|
|
1781
1827
|
printsToStdio() {
|
|
1782
|
-
return this._reporter.printsToStdio
|
|
1828
|
+
return this._reporter.printsToStdio?.() ?? true;
|
|
1783
1829
|
}
|
|
1784
1830
|
_addSnippetToTestErrors(test, result) {
|
|
1785
1831
|
for (const error of result.errors)
|
|
@@ -1813,7 +1859,7 @@ function addLocationAndSnippetToError(config2, error, file) {
|
|
|
1813
1859
|
}
|
|
1814
1860
|
|
|
1815
1861
|
// packages/playwright/src/runner/testRunner.ts
|
|
1816
|
-
var
|
|
1862
|
+
var import_util15 = require("../util");
|
|
1817
1863
|
|
|
1818
1864
|
// packages/playwright/src/runner/reporters.ts
|
|
1819
1865
|
var reporters_exports = {};
|
|
@@ -2040,7 +2086,7 @@ var OutOfProcessLoaderHost = class {
|
|
|
2040
2086
|
};
|
|
2041
2087
|
|
|
2042
2088
|
// packages/playwright/src/runner/loadUtils.ts
|
|
2043
|
-
var
|
|
2089
|
+
var import_util6 = require("../util");
|
|
2044
2090
|
|
|
2045
2091
|
// packages/playwright/src/runner/projectUtils.ts
|
|
2046
2092
|
var projectUtils_exports = {};
|
|
@@ -2054,12 +2100,12 @@ __export(projectUtils_exports, {
|
|
|
2054
2100
|
});
|
|
2055
2101
|
var import_fs2 = __toESM(require("fs"));
|
|
2056
2102
|
var import_path3 = __toESM(require("path"));
|
|
2057
|
-
var
|
|
2058
|
-
var
|
|
2059
|
-
var minimatch = require("playwright-core/lib/utilsBundle")
|
|
2103
|
+
var import_util4 = require("util");
|
|
2104
|
+
var import_util5 = require("../util");
|
|
2105
|
+
var { minimatch } = require("playwright-core/lib/utilsBundle");
|
|
2060
2106
|
var { escapeRegExp } = require("playwright-core/lib/coreBundle").iso;
|
|
2061
|
-
var readFileAsync = (0,
|
|
2062
|
-
var readDirAsync = (0,
|
|
2107
|
+
var readFileAsync = (0, import_util4.promisify)(import_fs2.default.readFile);
|
|
2108
|
+
var readDirAsync = (0, import_util4.promisify)(import_fs2.default.readdir);
|
|
2063
2109
|
function wildcardPatternToRegExp(pattern) {
|
|
2064
2110
|
return new RegExp("^" + pattern.split("*").map(escapeRegExp).join(".*") + "$", "ig");
|
|
2065
2111
|
}
|
|
@@ -2164,8 +2210,8 @@ async function collectFilesForProject(project, fsCache = /* @__PURE__ */ new Map
|
|
|
2164
2210
|
const extensions = /* @__PURE__ */ new Set([".js", ".ts", ".mjs", ".mts", ".cjs", ".cts", ".jsx", ".tsx", ".mjsx", ".mtsx", ".cjsx", ".ctsx"]);
|
|
2165
2211
|
const testFileExtension = (file) => extensions.has(import_path3.default.extname(file));
|
|
2166
2212
|
const allFiles = await cachedCollectFiles(project.project.testDir, project.respectGitIgnore, fsCache);
|
|
2167
|
-
const testMatch = (0,
|
|
2168
|
-
const testIgnore = (0,
|
|
2213
|
+
const testMatch = (0, import_util5.createFileMatcher)(project.project.testMatch);
|
|
2214
|
+
const testIgnore = (0, import_util5.createFileMatcher)(project.project.testIgnore);
|
|
2169
2215
|
const testFiles = allFiles.filter((file) => {
|
|
2170
2216
|
if (!testFileExtension(file))
|
|
2171
2217
|
return false;
|
|
@@ -2247,6 +2293,65 @@ async function collectFiles(testDir, respectGitIgnore) {
|
|
|
2247
2293
|
return files;
|
|
2248
2294
|
}
|
|
2249
2295
|
|
|
2296
|
+
// packages/playwright/src/runner/reporterTestRun.ts
|
|
2297
|
+
var import_common3 = require("../common");
|
|
2298
|
+
var ReporterTestRunImpl = class {
|
|
2299
|
+
constructor(_rootSuite, _readonlyProjectSuites) {
|
|
2300
|
+
this._rootSuite = _rootSuite;
|
|
2301
|
+
this._readonlyProjectSuites = _readonlyProjectSuites;
|
|
2302
|
+
this._active = true;
|
|
2303
|
+
this._skipSharding = false;
|
|
2304
|
+
this.skip = import_common3.transform.wrapFunctionWithLocation((location, target, reason) => this._modifier("skip", location, target, reason));
|
|
2305
|
+
this.fixme = import_common3.transform.wrapFunctionWithLocation((location, target, reason) => this._modifier("fixme", location, target, reason));
|
|
2306
|
+
this.fail = import_common3.transform.wrapFunctionWithLocation((location, target, reason) => this._modifier("fail", location, target, reason));
|
|
2307
|
+
}
|
|
2308
|
+
close() {
|
|
2309
|
+
this._active = false;
|
|
2310
|
+
}
|
|
2311
|
+
shouldSkipSharding() {
|
|
2312
|
+
return this._skipSharding;
|
|
2313
|
+
}
|
|
2314
|
+
skipSharding() {
|
|
2315
|
+
if (!this._active)
|
|
2316
|
+
throw new Error(`TestRun.skipSharding() can only be called from Reporter.preprocess().`);
|
|
2317
|
+
if (this._skipSharding)
|
|
2318
|
+
throw new Error(`Multiple reporters called 'skipSharding'. Only one reporter may handle sharding.`);
|
|
2319
|
+
this._skipSharding = true;
|
|
2320
|
+
}
|
|
2321
|
+
exclude(target) {
|
|
2322
|
+
if (!this._active)
|
|
2323
|
+
throw new Error(`TestRun.exclude() can only be called from Reporter.preprocess().`);
|
|
2324
|
+
const internalTarget = target;
|
|
2325
|
+
this._checkTarget("exclude", internalTarget);
|
|
2326
|
+
internalTarget.parent._detach(internalTarget);
|
|
2327
|
+
}
|
|
2328
|
+
_modifier(type, location, _target, reason) {
|
|
2329
|
+
if (!this._active)
|
|
2330
|
+
throw new Error(`TestRun.${type}() can only be called from Reporter.preprocess().`);
|
|
2331
|
+
const target = _target;
|
|
2332
|
+
this._checkTarget(type, target);
|
|
2333
|
+
const annotation = { type, description: reason, location };
|
|
2334
|
+
if (target instanceof import_common3.test.Suite) {
|
|
2335
|
+
for (const test of target.allTests())
|
|
2336
|
+
test._applyPlanAnnotation(annotation);
|
|
2337
|
+
} else {
|
|
2338
|
+
target._applyPlanAnnotation(annotation);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
_checkTarget(method, target) {
|
|
2342
|
+
if (target === this._rootSuite)
|
|
2343
|
+
throw new Error(`TestRun.${method}() cannot be called on the root suite.`);
|
|
2344
|
+
let suite = target instanceof import_common3.test.Suite ? target : target.parent;
|
|
2345
|
+
while (suite) {
|
|
2346
|
+
if (this._readonlyProjectSuites.has(suite)) {
|
|
2347
|
+
const targetType = target instanceof import_common3.test.TestCase ? " test" : "";
|
|
2348
|
+
throw new Error(`TestRun.${method}() cannot be called on a setup or teardown project${targetType}; these always run in full.`);
|
|
2349
|
+
}
|
|
2350
|
+
suite = suite.parent;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
};
|
|
2354
|
+
|
|
2250
2355
|
// packages/playwright/src/runner/testGroups.ts
|
|
2251
2356
|
function createTestGroups(projectSuite, expectedParallelism) {
|
|
2252
2357
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -2346,7 +2451,7 @@ function filterForShard(shard, weights, testGroups) {
|
|
|
2346
2451
|
}
|
|
2347
2452
|
|
|
2348
2453
|
// packages/playwright/src/runner/loadUtils.ts
|
|
2349
|
-
var
|
|
2454
|
+
var import_common4 = require("../common");
|
|
2350
2455
|
var sourceMapSupport = require("playwright-core/lib/utilsBundle").sourceMapSupport;
|
|
2351
2456
|
var { toPosixPath } = require("playwright-core/lib/coreBundle").utils;
|
|
2352
2457
|
async function collectProjectsAndTestFiles(testRun, doNotRunTestsOutsideProjectFilter) {
|
|
@@ -2399,7 +2504,7 @@ async function loadFileSuites(testRun, mode, errors) {
|
|
|
2399
2504
|
await loaderHost.stop();
|
|
2400
2505
|
}
|
|
2401
2506
|
for (const file of allTestFiles) {
|
|
2402
|
-
for (const dependency of
|
|
2507
|
+
for (const dependency of import_common4.cc.dependenciesForTestFile(file)) {
|
|
2403
2508
|
if (allTestFiles.has(dependency)) {
|
|
2404
2509
|
const importer = import_path4.default.relative(config2.config.rootDir, file);
|
|
2405
2510
|
const importee = import_path4.default.relative(config2.config.rootDir, dependency);
|
|
@@ -2417,7 +2522,7 @@ async function loadFileSuites(testRun, mode, errors) {
|
|
|
2417
2522
|
}
|
|
2418
2523
|
async function createRootSuite(testRun, errors, shouldFilterOnly) {
|
|
2419
2524
|
const config2 = testRun.config;
|
|
2420
|
-
const rootSuite = new
|
|
2525
|
+
const rootSuite = new import_common4.test.Suite("", "root");
|
|
2421
2526
|
const projectSuites = /* @__PURE__ */ new Map();
|
|
2422
2527
|
const filteredProjectSuites = /* @__PURE__ */ new Map();
|
|
2423
2528
|
{
|
|
@@ -2429,10 +2534,10 @@ async function createRootSuite(testRun, errors, shouldFilterOnly) {
|
|
|
2429
2534
|
}
|
|
2430
2535
|
}
|
|
2431
2536
|
if (shouldFilterOnly) {
|
|
2432
|
-
const filteredRoot = new
|
|
2537
|
+
const filteredRoot = new import_common4.test.Suite("", "root");
|
|
2433
2538
|
for (const filteredProjectSuite of filteredProjectSuites.values())
|
|
2434
2539
|
filteredRoot._addSuite(filteredProjectSuite);
|
|
2435
|
-
|
|
2540
|
+
import_common4.suiteUtils.filterOnly(filteredRoot);
|
|
2436
2541
|
for (const [project, filteredProjectSuite] of filteredProjectSuites) {
|
|
2437
2542
|
if (!filteredRoot.suites.includes(filteredProjectSuite))
|
|
2438
2543
|
filteredProjectSuites.delete(project);
|
|
@@ -2452,7 +2557,24 @@ async function createRootSuite(testRun, errors, shouldFilterOnly) {
|
|
|
2452
2557
|
errors.push(...createForbidOnlyErrors(onlyTestsAndSuites, config2.configCLIOverrides.forbidOnly, configFilePath));
|
|
2453
2558
|
}
|
|
2454
2559
|
}
|
|
2455
|
-
|
|
2560
|
+
const dependencySuites = /* @__PURE__ */ new Map();
|
|
2561
|
+
for (const [project, type] of projectClosure) {
|
|
2562
|
+
if (type !== "dependency")
|
|
2563
|
+
continue;
|
|
2564
|
+
const dependencySuite = buildProjectSuite(project, projectSuites.get(project));
|
|
2565
|
+
dependencySuites.set(project, dependencySuite);
|
|
2566
|
+
rootSuite._prependSuite(dependencySuite);
|
|
2567
|
+
}
|
|
2568
|
+
const reporterTestRun = new ReporterTestRunImpl(rootSuite, new Set(dependencySuites.values()));
|
|
2569
|
+
await testRun.reporter.preprocess({
|
|
2570
|
+
config: config2.config,
|
|
2571
|
+
suite: rootSuite,
|
|
2572
|
+
testRun: reporterTestRun
|
|
2573
|
+
});
|
|
2574
|
+
reporterTestRun.close();
|
|
2575
|
+
for (const dependencySuite of dependencySuites.values())
|
|
2576
|
+
rootSuite._detach(dependencySuite);
|
|
2577
|
+
if (config2.config.shard && !reporterTestRun.shouldSkipSharding()) {
|
|
2456
2578
|
const testGroups = [];
|
|
2457
2579
|
for (const projectSuite of rootSuite.suites) {
|
|
2458
2580
|
for (const group of createTestGroups(projectSuite, config2.config.shard.total))
|
|
@@ -2464,30 +2586,31 @@ async function createRootSuite(testRun, errors, shouldFilterOnly) {
|
|
|
2464
2586
|
for (const test of group.tests)
|
|
2465
2587
|
testsInThisShard.add(test);
|
|
2466
2588
|
}
|
|
2467
|
-
|
|
2589
|
+
import_common4.suiteUtils.filterTestsRemoveEmptySuites(rootSuite, (test) => testsInThisShard.has(test));
|
|
2468
2590
|
}
|
|
2469
2591
|
if (testRun.postShardTestFilters.length)
|
|
2470
|
-
|
|
2592
|
+
import_common4.suiteUtils.filterTestsRemoveEmptySuites(rootSuite, (test) => testRun.postShardTestFilters.every((filter) => filter(test)));
|
|
2471
2593
|
const topLevelProjects = [];
|
|
2472
2594
|
{
|
|
2473
|
-
const
|
|
2474
|
-
for (const [project,
|
|
2475
|
-
if (
|
|
2476
|
-
rootSuite.
|
|
2595
|
+
const finalProjectClosure = buildProjectsClosure(rootSuite.suites.map((suite) => suite._fullProject));
|
|
2596
|
+
for (const [project, type] of finalProjectClosure) {
|
|
2597
|
+
if (type === "dependency")
|
|
2598
|
+
rootSuite._addSuite(dependencySuites.get(project));
|
|
2477
2599
|
else
|
|
2478
2600
|
topLevelProjects.push(project);
|
|
2479
2601
|
}
|
|
2480
2602
|
}
|
|
2603
|
+
rootSuite._entries.sort((a, b) => config2.projects.indexOf(a._fullProject) - config2.projects.indexOf(b._fullProject));
|
|
2481
2604
|
testRun.rootSuite = rootSuite;
|
|
2482
2605
|
testRun.topLevelProjects = topLevelProjects;
|
|
2483
2606
|
}
|
|
2484
2607
|
function createProjectSuite(project, fileSuites) {
|
|
2485
|
-
const projectSuite = new
|
|
2608
|
+
const projectSuite = new import_common4.test.Suite(project.project.name, "project");
|
|
2486
2609
|
for (const fileSuite of fileSuites)
|
|
2487
|
-
projectSuite._addSuite(
|
|
2488
|
-
const grepMatcher = (0,
|
|
2489
|
-
const grepInvertMatcher = project.project.grepInvert ? (0,
|
|
2490
|
-
|
|
2610
|
+
projectSuite._addSuite(import_common4.suiteUtils.bindFileSuiteToProject(project, fileSuite));
|
|
2611
|
+
const grepMatcher = (0, import_util6.createTitleMatcher)(project.project.grep);
|
|
2612
|
+
const grepInvertMatcher = project.project.grepInvert ? (0, import_util6.createTitleMatcher)(project.project.grepInvert) : null;
|
|
2613
|
+
import_common4.suiteUtils.filterTestsRemoveEmptySuites(projectSuite, (test) => {
|
|
2491
2614
|
const grepTitle = test._grepTitleWithTags();
|
|
2492
2615
|
if (grepInvertMatcher?.(grepTitle))
|
|
2493
2616
|
return false;
|
|
@@ -2499,11 +2622,11 @@ function filterProjectSuite(projectSuite, testFilters) {
|
|
|
2499
2622
|
if (!testFilters.length)
|
|
2500
2623
|
return projectSuite;
|
|
2501
2624
|
const result = projectSuite._deepClone();
|
|
2502
|
-
|
|
2625
|
+
import_common4.suiteUtils.filterTestsRemoveEmptySuites(result, (test) => testFilters.every((filter) => filter(test)));
|
|
2503
2626
|
return result;
|
|
2504
2627
|
}
|
|
2505
2628
|
function buildProjectSuite(project, projectSuite) {
|
|
2506
|
-
const result = new
|
|
2629
|
+
const result = new import_common4.test.Suite(project.project.name, "project");
|
|
2507
2630
|
result._fullProject = project;
|
|
2508
2631
|
if (project.fullyParallel)
|
|
2509
2632
|
result._parallelMode = "parallel";
|
|
@@ -2511,7 +2634,7 @@ function buildProjectSuite(project, projectSuite) {
|
|
|
2511
2634
|
result._addSuite(fileSuite);
|
|
2512
2635
|
for (let repeatEachIndex = 1; repeatEachIndex < project.project.repeatEach; repeatEachIndex++) {
|
|
2513
2636
|
const clone = fileSuite._deepClone();
|
|
2514
|
-
|
|
2637
|
+
import_common4.suiteUtils.applyRepeatEachIndex(project, clone, repeatEachIndex);
|
|
2515
2638
|
result._addSuite(clone);
|
|
2516
2639
|
}
|
|
2517
2640
|
}
|
|
@@ -2554,11 +2677,11 @@ function buildItemLocation(rootDir, testOrSuite) {
|
|
|
2554
2677
|
return `${import_path4.default.relative(rootDir, testOrSuite.location.file)}:${testOrSuite.location.line}`;
|
|
2555
2678
|
}
|
|
2556
2679
|
async function requireOrImportDefaultFunction(file, expectConstructor) {
|
|
2557
|
-
let func = await
|
|
2680
|
+
let func = await import_common4.transform.requireOrImport(file);
|
|
2558
2681
|
if (func && typeof func === "object" && "default" in func)
|
|
2559
2682
|
func = func["default"];
|
|
2560
2683
|
if (typeof func !== "function")
|
|
2561
|
-
throw (0,
|
|
2684
|
+
throw (0, import_util6.errorWithFile)(file, `file must export a single ${expectConstructor ? "class" : "function"}.`);
|
|
2562
2685
|
return func;
|
|
2563
2686
|
}
|
|
2564
2687
|
function loadGlobalHook(config2, file) {
|
|
@@ -2597,7 +2720,7 @@ async function loadTestList(config2, filePath) {
|
|
|
2597
2720
|
project = tokens[0].substring(1, tokens[0].length - 1);
|
|
2598
2721
|
tokens.shift();
|
|
2599
2722
|
}
|
|
2600
|
-
return { project, file: toPosixPath((0,
|
|
2723
|
+
return { project, file: toPosixPath((0, import_util6.parseLocationArg)(tokens[0]).file), titlePath: tokens.slice(1) };
|
|
2601
2724
|
});
|
|
2602
2725
|
const testFilter = (test) => descriptions.some((d) => {
|
|
2603
2726
|
const [projectName, , ...titles] = test.titlePath();
|
|
@@ -2614,7 +2737,7 @@ async function loadTestList(config2, filePath) {
|
|
|
2614
2737
|
};
|
|
2615
2738
|
return { testFilter, fileFilter };
|
|
2616
2739
|
} catch (e) {
|
|
2617
|
-
throw (0,
|
|
2740
|
+
throw (0, import_util6.errorWithFile)(filePath, "Cannot read test list file: " + e.message);
|
|
2618
2741
|
}
|
|
2619
2742
|
}
|
|
2620
2743
|
|
|
@@ -2633,7 +2756,7 @@ var TeleReporterEmitter = class {
|
|
|
2633
2756
|
this._resultKnownErrorCounts = /* @__PURE__ */ new Map();
|
|
2634
2757
|
// In case there is blob reporter and UI mode, make sure one doesn't override
|
|
2635
2758
|
// the id assigned by the other.
|
|
2636
|
-
this._idSymbol = Symbol("id");
|
|
2759
|
+
this._idSymbol = /* @__PURE__ */ Symbol("id");
|
|
2637
2760
|
this._messageSink = messageSink;
|
|
2638
2761
|
this._emitterOptions = options;
|
|
2639
2762
|
}
|
|
@@ -3102,14 +3225,17 @@ var empty_default = EmptyReporter;
|
|
|
3102
3225
|
|
|
3103
3226
|
// packages/playwright/src/reporters/github.ts
|
|
3104
3227
|
var import_path7 = __toESM(require("path"));
|
|
3105
|
-
var
|
|
3228
|
+
var import_util7 = require("../util");
|
|
3106
3229
|
var { noColors: noColors2 } = require("playwright-core/lib/coreBundle").iso;
|
|
3107
3230
|
var { msToString: msToString2 } = require("playwright-core/lib/coreBundle").iso;
|
|
3108
3231
|
var GitHubLogger = class {
|
|
3232
|
+
newLine() {
|
|
3233
|
+
process.stdout.write("\n");
|
|
3234
|
+
}
|
|
3109
3235
|
_log(message, type = "notice", options = {}) {
|
|
3110
3236
|
message = message.replace(/\n/g, "%0A");
|
|
3111
3237
|
const configs = Object.entries(options).map(([key, option]) => `${key}=${option}`).join(",");
|
|
3112
|
-
process.stdout.write((0,
|
|
3238
|
+
process.stdout.write((0, import_util7.stripAnsiEscapes)(`::${type} ${configs}::${message}
|
|
3113
3239
|
`));
|
|
3114
3240
|
}
|
|
3115
3241
|
debug(message, options) {
|
|
@@ -3142,6 +3268,7 @@ var GitHubReporter = class extends TerminalReporter {
|
|
|
3142
3268
|
if (!this._shouldPrintFailureAnnotations(test))
|
|
3143
3269
|
return;
|
|
3144
3270
|
this._failedTestCount++;
|
|
3271
|
+
this.githubLogger.newLine();
|
|
3145
3272
|
for (const r of test.results)
|
|
3146
3273
|
this._printFailureAnnotation(test, r, this._failedTestCount);
|
|
3147
3274
|
}
|
|
@@ -3218,7 +3345,7 @@ var import_os = __toESM(require("os"));
|
|
|
3218
3345
|
var import_path8 = __toESM(require("path"));
|
|
3219
3346
|
var import_stream3 = require("stream");
|
|
3220
3347
|
var babel2 = __toESM(require("../transform/babelBundle"));
|
|
3221
|
-
var
|
|
3348
|
+
var import_util8 = require("../util");
|
|
3222
3349
|
var colors2 = require("playwright-core/lib/utilsBundle").colors;
|
|
3223
3350
|
var mime2 = require("playwright-core/lib/utilsBundle").mime;
|
|
3224
3351
|
var open = require("playwright-core/lib/utilsBundle").open;
|
|
@@ -3276,7 +3403,7 @@ var HtmlReporter = class {
|
|
|
3276
3403
|
this.suite = suite;
|
|
3277
3404
|
}
|
|
3278
3405
|
_resolveOptions() {
|
|
3279
|
-
const outputFolder = reportFolderFromEnv() ?? (0,
|
|
3406
|
+
const outputFolder = reportFolderFromEnv() ?? (0, import_util8.resolveReporterOutputPath)("playwright-report", this._options.configDir, this._options.outputFolder);
|
|
3280
3407
|
return {
|
|
3281
3408
|
outputFolder,
|
|
3282
3409
|
open: getHtmlReportOptionProcessEnv() || this._options.open || "on-failure",
|
|
@@ -3306,10 +3433,12 @@ var HtmlReporter = class {
|
|
|
3306
3433
|
const noSnippets = parseBooleanEnvVar("PLAYWRIGHT_HTML_NO_SNIPPETS") ?? this._options.noSnippets;
|
|
3307
3434
|
const noCopyPrompt = parseBooleanEnvVar("PLAYWRIGHT_HTML_NO_COPY_PROMPT") ?? this._options.noCopyPrompt;
|
|
3308
3435
|
const doNotInlineAssets = parseBooleanEnvVar("PLAYWRIGHT_HTML_DO_NOT_INLINE_ASSETS") ?? this._options.doNotInlineAssets ?? false;
|
|
3436
|
+
const mergeFiles = parseBooleanEnvVar("PLAYWRIGHT_HTML_MERGE_FILES") ?? this._options.mergeFiles;
|
|
3309
3437
|
const builder = new HtmlBuilder(yazl2, this.config, this._outputFolder, this._attachmentsBaseURL, doNotInlineAssets, {
|
|
3310
3438
|
title: process.env.PLAYWRIGHT_HTML_TITLE || this._options.title,
|
|
3311
3439
|
noSnippets,
|
|
3312
|
-
noCopyPrompt
|
|
3440
|
+
noCopyPrompt,
|
|
3441
|
+
mergeFiles
|
|
3313
3442
|
});
|
|
3314
3443
|
this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors, this._machines);
|
|
3315
3444
|
}
|
|
@@ -3356,7 +3485,7 @@ function parseBooleanEnvVar(name) {
|
|
|
3356
3485
|
return void 0;
|
|
3357
3486
|
}
|
|
3358
3487
|
function standaloneDefaultFolder() {
|
|
3359
|
-
return reportFolderFromEnv() ?? (0,
|
|
3488
|
+
return reportFolderFromEnv() ?? (0, import_util8.resolveReporterOutputPath)("playwright-report", process.cwd(), void 0);
|
|
3360
3489
|
}
|
|
3361
3490
|
async function resolveReportFolder(reportPath) {
|
|
3362
3491
|
const stat = await import_fs5.default.promises.stat(reportPath).catch(() => null);
|
|
@@ -3621,10 +3750,10 @@ var HtmlBuilder = class {
|
|
|
3621
3750
|
this._hasTraces = true;
|
|
3622
3751
|
if ((a.name === "stdout" || a.name === "stderr") && a.contentType === "text/plain") {
|
|
3623
3752
|
if (lastAttachment && lastAttachment.name === a.name && lastAttachment.contentType === a.contentType) {
|
|
3624
|
-
lastAttachment.body += (0,
|
|
3753
|
+
lastAttachment.body += (0, import_util8.stripAnsiEscapes)(a.body);
|
|
3625
3754
|
return null;
|
|
3626
3755
|
}
|
|
3627
|
-
a.body = (0,
|
|
3756
|
+
a.body = (0, import_util8.stripAnsiEscapes)(a.body);
|
|
3628
3757
|
lastAttachment = a;
|
|
3629
3758
|
return a;
|
|
3630
3759
|
}
|
|
@@ -3855,7 +3984,7 @@ function createErrorCodeframe(message, location) {
|
|
|
3855
3984
|
highlightCode: false,
|
|
3856
3985
|
linesAbove: 100,
|
|
3857
3986
|
linesBelow: 100,
|
|
3858
|
-
message: (0,
|
|
3987
|
+
message: (0, import_util8.stripAnsiEscapes)(message).split("\n")[0] || void 0
|
|
3859
3988
|
}
|
|
3860
3989
|
);
|
|
3861
3990
|
}
|
|
@@ -3867,7 +3996,7 @@ var html_default = HtmlReporter;
|
|
|
3867
3996
|
// packages/playwright/src/reporters/json.ts
|
|
3868
3997
|
var import_fs6 = __toESM(require("fs"));
|
|
3869
3998
|
var import_path9 = __toESM(require("path"));
|
|
3870
|
-
var
|
|
3999
|
+
var import_common5 = require("../common");
|
|
3871
4000
|
var { MultiMap: MultiMap2 } = require("playwright-core/lib/coreBundle").iso;
|
|
3872
4001
|
var { toPosixPath: toPosixPath3 } = require("playwright-core/lib/coreBundle").utils;
|
|
3873
4002
|
var JSONReporter = class {
|
|
@@ -3904,7 +4033,7 @@ var JSONReporter = class {
|
|
|
3904
4033
|
repeatEach: project.repeatEach,
|
|
3905
4034
|
retries: project.retries,
|
|
3906
4035
|
metadata: project.metadata,
|
|
3907
|
-
id:
|
|
4036
|
+
id: import_common5.config.getProjectId(project),
|
|
3908
4037
|
name: project.name,
|
|
3909
4038
|
testDir: toPosixPath3(project.testDir),
|
|
3910
4039
|
testIgnore: serializePatterns(project.testIgnore),
|
|
@@ -3931,7 +4060,7 @@ var JSONReporter = class {
|
|
|
3931
4060
|
_mergeSuites(suites) {
|
|
3932
4061
|
const fileSuites = new MultiMap2();
|
|
3933
4062
|
for (const projectSuite of suites) {
|
|
3934
|
-
const projectId =
|
|
4063
|
+
const projectId = import_common5.config.getProjectId(projectSuite.project());
|
|
3935
4064
|
const projectName = projectSuite.project().name;
|
|
3936
4065
|
for (const fileSuite of projectSuite.suites) {
|
|
3937
4066
|
const file = fileSuite.location.file;
|
|
@@ -4085,7 +4214,7 @@ var json_default = JSONReporter;
|
|
|
4085
4214
|
// packages/playwright/src/reporters/junit.ts
|
|
4086
4215
|
var import_fs7 = __toESM(require("fs"));
|
|
4087
4216
|
var import_path10 = __toESM(require("path"));
|
|
4088
|
-
var
|
|
4217
|
+
var import_util9 = require("../util");
|
|
4089
4218
|
var { getAsBooleanFromENV } = require("playwright-core/lib/coreBundle").utils;
|
|
4090
4219
|
var JUnitReporter = class {
|
|
4091
4220
|
constructor(options) {
|
|
@@ -4251,7 +4380,7 @@ var JUnitReporter = class {
|
|
|
4251
4380
|
entry.children.push({
|
|
4252
4381
|
name: errorInfo.elementName,
|
|
4253
4382
|
attributes: { message: errorInfo.message, type: errorInfo.type },
|
|
4254
|
-
text: (0,
|
|
4383
|
+
text: (0, import_util9.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test))
|
|
4255
4384
|
});
|
|
4256
4385
|
return errorInfo.elementName;
|
|
4257
4386
|
}
|
|
@@ -4261,7 +4390,7 @@ var JUnitReporter = class {
|
|
|
4261
4390
|
message: `${import_path10.default.basename(test.location.file)}:${test.location.line}:${test.location.column} ${test.title}`,
|
|
4262
4391
|
type: "FAILURE"
|
|
4263
4392
|
},
|
|
4264
|
-
text: (0,
|
|
4393
|
+
text: (0, import_util9.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test))
|
|
4265
4394
|
});
|
|
4266
4395
|
return "failure";
|
|
4267
4396
|
}
|
|
@@ -4308,7 +4437,7 @@ Warning: attachment ${attachmentPath} is missing`);
|
|
|
4308
4437
|
children: []
|
|
4309
4438
|
};
|
|
4310
4439
|
const stackTrace = result.error?.stack || result.error?.message || result.error?.value || "";
|
|
4311
|
-
entry.children.push({ name: "stackTrace", text: (0,
|
|
4440
|
+
entry.children.push({ name: "stackTrace", text: (0, import_util9.stripAnsiEscapes)(stackTrace) });
|
|
4312
4441
|
await this._appendStdIO(entry, [result]);
|
|
4313
4442
|
return entry;
|
|
4314
4443
|
}
|
|
@@ -4317,7 +4446,7 @@ function classifyResultError(result) {
|
|
|
4317
4446
|
const error = result.error;
|
|
4318
4447
|
if (!error)
|
|
4319
4448
|
return null;
|
|
4320
|
-
const rawMessage = (0,
|
|
4449
|
+
const rawMessage = (0, import_util9.stripAnsiEscapes)(error.message || error.value || "");
|
|
4321
4450
|
const nameMatch = rawMessage.match(/^(\w+): /);
|
|
4322
4451
|
const errorName = nameMatch ? nameMatch[1] : "";
|
|
4323
4452
|
const messageBody = nameMatch ? rawMessage.slice(nameMatch[0].length) : rawMessage;
|
|
@@ -4359,7 +4488,7 @@ function serializeXML(entry, tokens, stripANSIControlSequences) {
|
|
|
4359
4488
|
var discouragedXMLCharacters = /[\u0000-\u0008\u000b-\u000c\u000e-\u001f\u007f-\u0084\u0086-\u009f]/g;
|
|
4360
4489
|
function escape(text, stripANSIControlSequences, isCharacterData) {
|
|
4361
4490
|
if (stripANSIControlSequences)
|
|
4362
|
-
text = (0,
|
|
4491
|
+
text = (0, import_util9.stripAnsiEscapes)(text);
|
|
4363
4492
|
if (isCharacterData) {
|
|
4364
4493
|
text = "<![CDATA[" + text.replace(/]]>/g, "]]>") + "]]>";
|
|
4365
4494
|
} else {
|
|
@@ -4481,7 +4610,7 @@ var LineReporter = class extends TerminalReporter {
|
|
|
4481
4610
|
var line_default = LineReporter;
|
|
4482
4611
|
|
|
4483
4612
|
// packages/playwright/src/reporters/list.ts
|
|
4484
|
-
var
|
|
4613
|
+
var import_util10 = require("../util");
|
|
4485
4614
|
var { msToString: msToString3 } = require("playwright-core/lib/coreBundle").iso;
|
|
4486
4615
|
var { getAsBooleanFromENV: getAsBooleanFromENV2 } = require("playwright-core/lib/coreBundle").utils;
|
|
4487
4616
|
var DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === "win32" && process.env.TERM_PROGRAM !== "vscode" && !process.env.WT_SESSION;
|
|
@@ -4699,7 +4828,7 @@ var ListReporter = class extends TerminalReporter {
|
|
|
4699
4828
|
this.screen.stdout.write(`\x1B[${this._lastRow - row}E`);
|
|
4700
4829
|
}
|
|
4701
4830
|
_testPrefix(index, statusMark) {
|
|
4702
|
-
const statusMarkLength = (0,
|
|
4831
|
+
const statusMarkLength = (0, import_util10.stripAnsiEscapes)(statusMark).length;
|
|
4703
4832
|
const indexLength = Math.ceil(Math.log10(this.totalTestCount + 1));
|
|
4704
4833
|
return " " + statusMark + " ".repeat(3 - statusMarkLength) + this.screen.colors.dim(index.padStart(indexLength) + " ");
|
|
4705
4834
|
}
|
|
@@ -4719,7 +4848,7 @@ var ListReporter = class extends TerminalReporter {
|
|
|
4719
4848
|
this.epilogue(!this._printFailuresInline);
|
|
4720
4849
|
}
|
|
4721
4850
|
};
|
|
4722
|
-
var lastStepOrdinalSymbol = Symbol("lastStepOrdinal");
|
|
4851
|
+
var lastStepOrdinalSymbol = /* @__PURE__ */ Symbol("lastStepOrdinal");
|
|
4723
4852
|
var list_default = ListReporter;
|
|
4724
4853
|
|
|
4725
4854
|
// packages/playwright/src/reporters/listModeReporter.ts
|
|
@@ -4762,26 +4891,124 @@ var listModeReporter_default = ListModeReporter;
|
|
|
4762
4891
|
// packages/playwright/src/reporters/smoothdeploy.ts
|
|
4763
4892
|
var fs9 = __toESM(require("fs"));
|
|
4764
4893
|
var path12 = __toESM(require("path"));
|
|
4894
|
+
|
|
4895
|
+
// packages/playwright/src/reporters/smoothdeployMatch.ts
|
|
4896
|
+
var ACTION_API = {
|
|
4897
|
+
navigate: ["Frame.goto"],
|
|
4898
|
+
click: ["Frame.click", "Frame.dblclick", "Frame.dispatchEvent"],
|
|
4899
|
+
fill: ["Frame.fill"],
|
|
4900
|
+
press: ["Frame.press"],
|
|
4901
|
+
hover: ["Frame.hover"],
|
|
4902
|
+
check: ["Frame.check"],
|
|
4903
|
+
uncheck: ["Frame.uncheck"],
|
|
4904
|
+
select: ["Frame.selectOption"],
|
|
4905
|
+
setInputFiles: ["Frame.setInputFiles", "ElementHandle.setInputFiles"],
|
|
4906
|
+
openPage: ["BrowserContext.newPage"],
|
|
4907
|
+
closePage: ["Page.close"],
|
|
4908
|
+
assertVisible: ["toBeVisible"],
|
|
4909
|
+
assertText: ["toContainText", "toHaveText"],
|
|
4910
|
+
assertValue: ["toHaveValue", "toBeEmpty"],
|
|
4911
|
+
assertChecked: ["toBeChecked", "not.toBeChecked"],
|
|
4912
|
+
assertSnapshot: ["toHaveScreenshot", "toMatchAriaSnapshot"]
|
|
4913
|
+
};
|
|
4914
|
+
var FILLER_API_NEVER_SKIPS_AHEAD = /* @__PURE__ */ new Set(["Frame.dispatchEvent"]);
|
|
4915
|
+
function stepApi(step) {
|
|
4916
|
+
if (step.category === "pw:api")
|
|
4917
|
+
return step.channelMethod ?? null;
|
|
4918
|
+
return normalizeApiName(step.apiName);
|
|
4919
|
+
}
|
|
4920
|
+
function shortApi(step) {
|
|
4921
|
+
const api = stepApi(step);
|
|
4922
|
+
if (!api)
|
|
4923
|
+
return null;
|
|
4924
|
+
const idx = api.lastIndexOf(".");
|
|
4925
|
+
return step.category === "pw:api" && idx >= 0 ? api.slice(idx + 1) : api;
|
|
4926
|
+
}
|
|
4927
|
+
function normalizeApiName(apiName) {
|
|
4928
|
+
if (!apiName)
|
|
4929
|
+
return null;
|
|
4930
|
+
if (apiName.startsWith("expect")) {
|
|
4931
|
+
if (apiName.includes(".poll") || apiName.includes(".soft"))
|
|
4932
|
+
return null;
|
|
4933
|
+
const matcher = apiName.slice("expect".length).replace(/^\./, "");
|
|
4934
|
+
return matcher || null;
|
|
4935
|
+
}
|
|
4936
|
+
const idx = apiName.lastIndexOf(".");
|
|
4937
|
+
return idx >= 0 ? apiName.slice(idx + 1) : apiName;
|
|
4938
|
+
}
|
|
4939
|
+
function apiMatches(step, expected) {
|
|
4940
|
+
const api = stepApi(step);
|
|
4941
|
+
if (!api)
|
|
4942
|
+
return false;
|
|
4943
|
+
const allowed = ACTION_API[expected.action];
|
|
4944
|
+
return !!allowed && allowed.includes(api);
|
|
4945
|
+
}
|
|
4946
|
+
function groupMatches(step, expected) {
|
|
4947
|
+
if (expected.title !== void 0)
|
|
4948
|
+
return step.title === expected.title;
|
|
4949
|
+
return expected.action === "group";
|
|
4950
|
+
}
|
|
4951
|
+
function stepMatches(step, expected) {
|
|
4952
|
+
if (step.category === "test.step")
|
|
4953
|
+
return groupMatches(step, expected);
|
|
4954
|
+
if (step.category === "pw:api" || step.category === "expect")
|
|
4955
|
+
return apiMatches(step, expected);
|
|
4956
|
+
return false;
|
|
4957
|
+
}
|
|
4958
|
+
function matchStep(step, siblings, cursor) {
|
|
4959
|
+
if (cursor < siblings.length && stepMatches(step, siblings[cursor]))
|
|
4960
|
+
return cursor;
|
|
4961
|
+
const api = stepApi(step);
|
|
4962
|
+
const canLookAhead = step.category === "test.step" ? siblings.some((s) => s.title !== void 0) : !!api && !FILLER_API_NEVER_SKIPS_AHEAD.has(api);
|
|
4963
|
+
if (!canLookAhead)
|
|
4964
|
+
return -1;
|
|
4965
|
+
for (let j = cursor + 1; j < siblings.length; j++) {
|
|
4966
|
+
if (stepMatches(step, siblings[j]))
|
|
4967
|
+
return j;
|
|
4968
|
+
}
|
|
4969
|
+
return -1;
|
|
4970
|
+
}
|
|
4971
|
+
var INTERNAL_STEP_TITLES = /* @__PURE__ */ new Set([
|
|
4972
|
+
"Before Hooks",
|
|
4973
|
+
"After Hooks",
|
|
4974
|
+
"Worker Cleanup",
|
|
4975
|
+
"Launch browser",
|
|
4976
|
+
"Launch persistent context",
|
|
4977
|
+
"Connect over CDP",
|
|
4978
|
+
"Close browser",
|
|
4979
|
+
"Create context",
|
|
4980
|
+
"Close context",
|
|
4981
|
+
"Create page",
|
|
4982
|
+
"Close page",
|
|
4983
|
+
"Create CDP session"
|
|
4984
|
+
]);
|
|
4985
|
+
function isToPassWrapper(step) {
|
|
4986
|
+
return normalizeApiName(step.apiName) === "toPass";
|
|
4987
|
+
}
|
|
4988
|
+
function isUserStep(step) {
|
|
4989
|
+
if (step.category === "hook" || step.category === "fixture" || step.category === "test.attach")
|
|
4990
|
+
return false;
|
|
4991
|
+
if (step.title.startsWith('Fixture "'))
|
|
4992
|
+
return false;
|
|
4993
|
+
return !INTERNAL_STEP_TITLES.has(step.title);
|
|
4994
|
+
}
|
|
4995
|
+
|
|
4996
|
+
// packages/playwright/src/reporters/smoothdeploy.ts
|
|
4997
|
+
var NO_SCREENSHOT_PREFIXES = ["Navigate", "Go back", "Go forward", "Reload", "Screenshot", "Wait for", "Pause", "Evaluate"];
|
|
4998
|
+
var safeId = (id) => id.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
4765
4999
|
var SmoothDeployReporter = class {
|
|
4766
5000
|
constructor() {
|
|
4767
5001
|
this._configDir = "";
|
|
4768
5002
|
this._manifest = null;
|
|
4769
|
-
// Resolved manifest test + paramIndex for each active pw test
|
|
4770
5003
|
this._resolvedTests = /* @__PURE__ */ new Map();
|
|
4771
|
-
|
|
4772
|
-
this.
|
|
4773
|
-
|
|
4774
|
-
this.
|
|
4775
|
-
// Accumulate nested step data per test for output manifest
|
|
5004
|
+
this._matched = /* @__PURE__ */ new WeakMap();
|
|
5005
|
+
this._opaqueFiller = /* @__PURE__ */ new WeakSet();
|
|
5006
|
+
this._retries = /* @__PURE__ */ new WeakMap();
|
|
5007
|
+
this._rootCursors = /* @__PURE__ */ new Map();
|
|
4776
5008
|
this._testSteps = /* @__PURE__ */ new Map();
|
|
4777
|
-
// Track parent step → output StepData for nesting output
|
|
4778
|
-
this._stepToOutput = /* @__PURE__ */ new WeakMap();
|
|
4779
|
-
// ID remap: pw IDs → manifest IDs (sanitized). Built during execution, applied in onEnd.
|
|
4780
5009
|
this._testIdMap = /* @__PURE__ */ new Map();
|
|
4781
|
-
// safePwTestId → safeManifestTestId
|
|
4782
5010
|
this._stepIdMap = /* @__PURE__ */ new Map();
|
|
4783
5011
|
}
|
|
4784
|
-
// safePwStepId → safeManifestStepId
|
|
4785
5012
|
version() {
|
|
4786
5013
|
return "v2";
|
|
4787
5014
|
}
|
|
@@ -4790,44 +5017,36 @@ var SmoothDeployReporter = class {
|
|
|
4790
5017
|
}
|
|
4791
5018
|
onConfigure(config2) {
|
|
4792
5019
|
this._configDir = config2.configFile ? path12.dirname(config2.configFile) : config2.rootDir;
|
|
4793
|
-
this._loadManifest();
|
|
4794
|
-
}
|
|
4795
|
-
_loadManifest() {
|
|
4796
5020
|
const manifestPath = path12.join(this._configDir, ".smoothdeploy-manifest.json");
|
|
4797
|
-
if (
|
|
4798
|
-
|
|
4799
|
-
const raw = fs9.readFileSync(manifestPath, "utf-8");
|
|
4800
|
-
this._manifest = JSON.parse(raw);
|
|
5021
|
+
if (fs9.existsSync(manifestPath))
|
|
5022
|
+
this._manifest = JSON.parse(fs9.readFileSync(manifestPath, "utf-8"));
|
|
4801
5023
|
}
|
|
4802
|
-
_emit(event) {
|
|
4803
|
-
|
|
5024
|
+
_emit(event, step) {
|
|
5025
|
+
const retry = step && this._nearestRetry(step);
|
|
5026
|
+
if (retry)
|
|
5027
|
+
retry.events.push(event);
|
|
5028
|
+
else
|
|
5029
|
+
process.stdout.write(`[SMOOTHDEPLOY_EVENT]${JSON.stringify(event)}
|
|
4804
5030
|
`);
|
|
4805
5031
|
}
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
"Launch browser",
|
|
4814
|
-
"Launch persistent context",
|
|
4815
|
-
"Connect over CDP",
|
|
4816
|
-
"Close browser",
|
|
4817
|
-
"Create context",
|
|
4818
|
-
"Close context",
|
|
4819
|
-
"Create page",
|
|
4820
|
-
"Close page",
|
|
4821
|
-
"Create CDP session"
|
|
4822
|
-
];
|
|
4823
|
-
if (internalSteps.includes(title))
|
|
4824
|
-
return false;
|
|
4825
|
-
return true;
|
|
5032
|
+
_nearestRetry(step) {
|
|
5033
|
+
for (let p = step.parent; p; p = p.parent) {
|
|
5034
|
+
const retry = this._retries.get(p);
|
|
5035
|
+
if (retry)
|
|
5036
|
+
return retry;
|
|
5037
|
+
}
|
|
5038
|
+
return void 0;
|
|
4826
5039
|
}
|
|
4827
|
-
// Resolve a pw TestCase to its manifest test entry + param index.
|
|
4828
|
-
// For parameterized tests: manifest title "Foo" with params=3 matches pw titles "Foo0", "Foo1", "Foo2".
|
|
4829
|
-
// For non-parameterized tests: exact match, paramIndex=0.
|
|
4830
5040
|
_resolveManifestTest(test) {
|
|
5041
|
+
const manifestTest = this._findManifestTest(test);
|
|
5042
|
+
if (!manifestTest)
|
|
5043
|
+
return { manifestTest: { id: test.id, title: test.title, steps: [] }, paramIndex: 0, passthrough: true };
|
|
5044
|
+
const single = manifestTest.manifestTest.steps.length === 1 ? manifestTest.manifestTest.steps[0] : void 0;
|
|
5045
|
+
if (single && single.action === "script")
|
|
5046
|
+
return { ...manifestTest, passthrough: true, passthroughRootId: single.id };
|
|
5047
|
+
return { ...manifestTest, passthrough: false };
|
|
5048
|
+
}
|
|
5049
|
+
_findManifestTest(test) {
|
|
4831
5050
|
if (!this._manifest)
|
|
4832
5051
|
return null;
|
|
4833
5052
|
const titlePath = test.titlePath();
|
|
@@ -4837,7 +5056,6 @@ var SmoothDeployReporter = class {
|
|
|
4837
5056
|
return null;
|
|
4838
5057
|
const fileIdx = titlePath.indexOf(relFile);
|
|
4839
5058
|
const describeTitles = fileIdx >= 0 ? titlePath.slice(fileIdx + 1, -1) : [];
|
|
4840
|
-
const testTitle = test.title;
|
|
4841
5059
|
let currentSuites = fileManifest.suites;
|
|
4842
5060
|
let currentTests = fileManifest.tests;
|
|
4843
5061
|
for (const desc of describeTitles) {
|
|
@@ -4847,15 +5065,13 @@ var SmoothDeployReporter = class {
|
|
|
4847
5065
|
currentSuites = suite.suites;
|
|
4848
5066
|
currentTests = suite.tests;
|
|
4849
5067
|
}
|
|
4850
|
-
const exactMatch = currentTests.find((t2) => t2.title ===
|
|
5068
|
+
const exactMatch = currentTests.find((t2) => t2.title === test.title);
|
|
4851
5069
|
if (exactMatch)
|
|
4852
5070
|
return { manifestTest: exactMatch, paramIndex: 0 };
|
|
4853
5071
|
for (const mt of currentTests) {
|
|
4854
|
-
if (!mt.params || mt.params < 1)
|
|
4855
|
-
continue;
|
|
4856
|
-
if (!testTitle.startsWith(mt.title))
|
|
5072
|
+
if (!mt.params || mt.params < 1 || !test.title.startsWith(mt.title))
|
|
4857
5073
|
continue;
|
|
4858
|
-
const suffix =
|
|
5074
|
+
const suffix = test.title.slice(mt.title.length);
|
|
4859
5075
|
const idx = parseInt(suffix, 10);
|
|
4860
5076
|
if (String(idx) === suffix && idx >= 0 && idx < mt.params)
|
|
4861
5077
|
return { manifestTest: mt, paramIndex: idx };
|
|
@@ -4864,13 +5080,9 @@ var SmoothDeployReporter = class {
|
|
|
4864
5080
|
}
|
|
4865
5081
|
onTestBegin(test, result) {
|
|
4866
5082
|
const resolved = this._resolveManifestTest(test);
|
|
4867
|
-
if (!resolved)
|
|
4868
|
-
return;
|
|
4869
5083
|
this._resolvedTests.set(test.id, resolved);
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
this._testIdMap.set(safePw, safeManifest);
|
|
4873
|
-
this._childCounters.set(test.id, 0);
|
|
5084
|
+
this._testIdMap.set(safeId(test.id), safeId(resolved.manifestTest.id));
|
|
5085
|
+
this._rootCursors.set(test.id, 0);
|
|
4874
5086
|
this._testSteps.set(test.id, []);
|
|
4875
5087
|
this._emit({
|
|
4876
5088
|
event: "testBegin",
|
|
@@ -4879,11 +5091,36 @@ var SmoothDeployReporter = class {
|
|
|
4879
5091
|
testTitle: test.title,
|
|
4880
5092
|
timestamp: Date.now()
|
|
4881
5093
|
});
|
|
5094
|
+
if (resolved.passthroughRootId) {
|
|
5095
|
+
this._emit({
|
|
5096
|
+
event: "stepBegin",
|
|
5097
|
+
testId: resolved.manifestTest.id,
|
|
5098
|
+
paramIndex: resolved.paramIndex,
|
|
5099
|
+
id: resolved.passthroughRootId,
|
|
5100
|
+
action: "script",
|
|
5101
|
+
title: test.title,
|
|
5102
|
+
category: "test.step",
|
|
5103
|
+
timestamp: Date.now()
|
|
5104
|
+
});
|
|
5105
|
+
}
|
|
4882
5106
|
}
|
|
4883
5107
|
onTestEnd(test, result) {
|
|
4884
5108
|
const resolved = this._resolvedTests.get(test.id);
|
|
4885
5109
|
if (!resolved)
|
|
4886
5110
|
return;
|
|
5111
|
+
if (resolved.passthroughRootId) {
|
|
5112
|
+
this._emit({
|
|
5113
|
+
event: "stepEnd",
|
|
5114
|
+
testId: resolved.manifestTest.id,
|
|
5115
|
+
paramIndex: resolved.paramIndex,
|
|
5116
|
+
id: resolved.passthroughRootId,
|
|
5117
|
+
action: "script",
|
|
5118
|
+
title: test.title,
|
|
5119
|
+
duration: result.duration,
|
|
5120
|
+
error: result.error ? { message: result.error.message } : null,
|
|
5121
|
+
timestamp: Date.now()
|
|
5122
|
+
});
|
|
5123
|
+
}
|
|
4887
5124
|
this._emit({
|
|
4888
5125
|
event: "testEnd",
|
|
4889
5126
|
testId: resolved.manifestTest.id,
|
|
@@ -4893,29 +5130,77 @@ var SmoothDeployReporter = class {
|
|
|
4893
5130
|
duration: result.duration,
|
|
4894
5131
|
timestamp: Date.now()
|
|
4895
5132
|
});
|
|
4896
|
-
this.
|
|
5133
|
+
this._rootCursors.delete(test.id);
|
|
5134
|
+
}
|
|
5135
|
+
_nearestMatchedAncestor(step) {
|
|
5136
|
+
for (let p = step.parent; p; p = p.parent) {
|
|
5137
|
+
const matched = this._matched.get(p);
|
|
5138
|
+
if (matched)
|
|
5139
|
+
return { matched, blocked: false };
|
|
5140
|
+
if (this._opaqueFiller.has(p))
|
|
5141
|
+
return { blocked: true };
|
|
5142
|
+
}
|
|
5143
|
+
return { blocked: false };
|
|
5144
|
+
}
|
|
5145
|
+
_resolveStep(test, resolved, step, parent) {
|
|
5146
|
+
const stepLike = { title: step.title, category: step.category, apiName: step._apiName, channelMethod: step._channelMethod };
|
|
5147
|
+
if (resolved.passthrough) {
|
|
5148
|
+
const index2 = parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0;
|
|
5149
|
+
const prefix = parent ? `${parent.manifest.id}:` : resolved.passthroughRootId ? `${resolved.passthroughRootId}:` : "";
|
|
5150
|
+
if (parent)
|
|
5151
|
+
parent.cursor = index2 + 1;
|
|
5152
|
+
else
|
|
5153
|
+
this._rootCursors.set(test.id, index2 + 1);
|
|
5154
|
+
const action = step.category === "test.step" ? "group" : shortApi(stepLike) ?? step.category;
|
|
5155
|
+
return { id: `${prefix}${index2}`, action, title: step.title, children: [] };
|
|
5156
|
+
}
|
|
5157
|
+
if (parent && parent.manifest.children.length === 0)
|
|
5158
|
+
return null;
|
|
5159
|
+
const siblings = parent ? parent.manifest.children : resolved.manifestTest.steps;
|
|
5160
|
+
const cursor = parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0;
|
|
5161
|
+
let index = matchStep(stepLike, siblings, cursor);
|
|
5162
|
+
const retry = this._nearestRetry(step);
|
|
5163
|
+
if (index < 0 && retry && retry.parent === parent && cursor > retry.startCursor) {
|
|
5164
|
+
index = matchStep(stepLike, siblings.slice(0, cursor), retry.startCursor);
|
|
5165
|
+
if (index >= 0)
|
|
5166
|
+
this._discardAttempt(test, retry);
|
|
5167
|
+
}
|
|
5168
|
+
if (index < 0)
|
|
5169
|
+
return null;
|
|
5170
|
+
if (parent)
|
|
5171
|
+
parent.cursor = index + 1;
|
|
5172
|
+
else
|
|
5173
|
+
this._rootCursors.set(test.id, index + 1);
|
|
5174
|
+
return siblings[index];
|
|
5175
|
+
}
|
|
5176
|
+
_discardAttempt(test, retry) {
|
|
5177
|
+
const list = retry.parent ? retry.parent.output.children : this._testSteps.get(test.id);
|
|
5178
|
+
for (const output of retry.outputs) {
|
|
5179
|
+
const i = list ? list.indexOf(output) : -1;
|
|
5180
|
+
if (i >= 0)
|
|
5181
|
+
list.splice(i, 1);
|
|
5182
|
+
}
|
|
5183
|
+
retry.outputs = [];
|
|
5184
|
+
retry.events = [];
|
|
4897
5185
|
}
|
|
4898
5186
|
onStepBegin(test, result, step) {
|
|
4899
|
-
if (!
|
|
5187
|
+
if (!isUserStep(step))
|
|
4900
5188
|
return;
|
|
4901
5189
|
const resolved = this._resolvedTests.get(test.id);
|
|
4902
5190
|
if (!resolved)
|
|
4903
5191
|
return;
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
const outputStep = {
|
|
4917
|
-
id: manifestStep?.id,
|
|
4918
|
-
action: manifestStep?.action,
|
|
5192
|
+
const { matched: parent, blocked } = this._nearestMatchedAncestor(step);
|
|
5193
|
+
const manifestStep = blocked ? null : this._resolveStep(test, resolved, step, parent);
|
|
5194
|
+
if (!manifestStep) {
|
|
5195
|
+
if (blocked || !isToPassWrapper({ title: step.title, category: step.category, apiName: step._apiName }))
|
|
5196
|
+
this._opaqueFiller.add(step);
|
|
5197
|
+
else
|
|
5198
|
+
this._retries.set(step, { parent, startCursor: parent ? parent.cursor : this._rootCursors.get(test.id) ?? 0, events: [], outputs: [] });
|
|
5199
|
+
return;
|
|
5200
|
+
}
|
|
5201
|
+
const output = {
|
|
5202
|
+
id: manifestStep.id,
|
|
5203
|
+
action: manifestStep.action,
|
|
4919
5204
|
title: step.title,
|
|
4920
5205
|
category: step.category,
|
|
4921
5206
|
duration: 0,
|
|
@@ -4923,97 +5208,106 @@ var SmoothDeployReporter = class {
|
|
|
4923
5208
|
screenshots: null,
|
|
4924
5209
|
children: []
|
|
4925
5210
|
};
|
|
4926
|
-
this.
|
|
4927
|
-
const
|
|
4928
|
-
if (
|
|
4929
|
-
|
|
5211
|
+
this._matched.set(step, { manifest: manifestStep, output, cursor: 0 });
|
|
5212
|
+
const retry = this._nearestRetry(step);
|
|
5213
|
+
if (retry && retry.parent === parent)
|
|
5214
|
+
retry.outputs.push(output);
|
|
5215
|
+
if (parent)
|
|
5216
|
+
parent.output.children.push(output);
|
|
4930
5217
|
else
|
|
4931
|
-
this._testSteps.get(test.id)?.push(
|
|
5218
|
+
this._testSteps.get(test.id)?.push(output);
|
|
4932
5219
|
this._emit({
|
|
4933
5220
|
event: "stepBegin",
|
|
4934
5221
|
testId: resolved.manifestTest.id,
|
|
4935
5222
|
paramIndex: resolved.paramIndex,
|
|
4936
|
-
id: manifestStep
|
|
4937
|
-
action: manifestStep
|
|
5223
|
+
id: manifestStep.id,
|
|
5224
|
+
action: manifestStep.action,
|
|
4938
5225
|
title: step.title,
|
|
4939
5226
|
category: step.category,
|
|
4940
5227
|
timestamp: Date.now()
|
|
4941
|
-
});
|
|
5228
|
+
}, step);
|
|
5229
|
+
}
|
|
5230
|
+
_screenshotsFor(test, step) {
|
|
5231
|
+
const hasScreenshot = step.category === "pw:api" && !NO_SCREENSHOT_PREFIXES.some((prefix) => step.title.startsWith(prefix));
|
|
5232
|
+
if (!hasScreenshot)
|
|
5233
|
+
return null;
|
|
5234
|
+
const safeStepId = safeId(step._stepId ?? step.title);
|
|
5235
|
+
return {
|
|
5236
|
+
safeStepId,
|
|
5237
|
+
paths: {
|
|
5238
|
+
page: `.smoothdeploy-output/screenshots/${safeId(test.id)}/${safeStepId}-page.png`,
|
|
5239
|
+
element: `.smoothdeploy-output/screenshots/${safeId(test.id)}/${safeStepId}-element.png`
|
|
5240
|
+
}
|
|
5241
|
+
};
|
|
4942
5242
|
}
|
|
4943
5243
|
onStepEnd(test, result, step) {
|
|
4944
|
-
if (!
|
|
5244
|
+
if (!isUserStep(step))
|
|
4945
5245
|
return;
|
|
4946
5246
|
const resolved = this._resolvedTests.get(test.id);
|
|
4947
5247
|
if (!resolved)
|
|
4948
5248
|
return;
|
|
4949
|
-
const
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
outputStep.error = step.error && !hasDescendantError(outputStep.children) ? { message: step.error.message ?? "" } : null;
|
|
4977
|
-
outputStep.screenshots = screenshots;
|
|
4978
|
-
}
|
|
4979
|
-
this._childCounters.delete(step);
|
|
5249
|
+
const retry = this._retries.get(step);
|
|
5250
|
+
if (retry) {
|
|
5251
|
+
this._retries.delete(step);
|
|
5252
|
+
for (const event of retry.events)
|
|
5253
|
+
this._emit(event, step);
|
|
5254
|
+
return;
|
|
5255
|
+
}
|
|
5256
|
+
const matched = this._matched.get(step);
|
|
5257
|
+
const screenshots = this._screenshotsFor(test, step);
|
|
5258
|
+
if (!matched) {
|
|
5259
|
+
const leaf = this._nearestMatchedAncestor(step).matched;
|
|
5260
|
+
if (screenshots && leaf && leaf.manifest.children.length === 0 && !leaf.output.screenshots) {
|
|
5261
|
+
this._stepIdMap.set(screenshots.safeStepId, safeId(leaf.manifest.id));
|
|
5262
|
+
leaf.output.screenshots = screenshots.paths;
|
|
5263
|
+
}
|
|
5264
|
+
return;
|
|
5265
|
+
}
|
|
5266
|
+
if (screenshots) {
|
|
5267
|
+
this._stepIdMap.set(screenshots.safeStepId, safeId(matched.manifest.id));
|
|
5268
|
+
matched.output.screenshots = screenshots.paths;
|
|
5269
|
+
}
|
|
5270
|
+
matched.output.duration = step.duration;
|
|
5271
|
+
const skipped = step.annotations.some((a) => a.type === "skip");
|
|
5272
|
+
if (skipped)
|
|
5273
|
+
matched.output.skipped = true;
|
|
5274
|
+
const hasDescendantError = (steps) => steps.some((c) => c.error !== null || hasDescendantError(c.children));
|
|
5275
|
+
matched.output.error = step.error && !hasDescendantError(matched.output.children) ? { message: step.error.message ?? "" } : null;
|
|
4980
5276
|
this._emit({
|
|
4981
5277
|
event: "stepEnd",
|
|
4982
5278
|
testId: resolved.manifestTest.id,
|
|
4983
5279
|
paramIndex: resolved.paramIndex,
|
|
4984
|
-
id:
|
|
4985
|
-
action:
|
|
5280
|
+
id: matched.manifest.id,
|
|
5281
|
+
action: matched.manifest.action,
|
|
4986
5282
|
title: step.title,
|
|
4987
5283
|
duration: step.duration,
|
|
4988
5284
|
error: step.error ? { message: step.error.message } : null,
|
|
5285
|
+
skipped,
|
|
4989
5286
|
timestamp: Date.now()
|
|
4990
|
-
});
|
|
5287
|
+
}, step);
|
|
4991
5288
|
}
|
|
4992
5289
|
onEnd(result) {
|
|
4993
5290
|
const outputDir = path12.join(process.cwd(), ".smoothdeploy-output");
|
|
4994
5291
|
const screenshotsDir = path12.join(outputDir, "screenshots");
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
for (const [
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
if (fs9.existsSync(src))
|
|
5005
|
-
fs9.renameSync(src, dst);
|
|
5006
|
-
}
|
|
5292
|
+
for (const [safePwTestId] of this._testIdMap) {
|
|
5293
|
+
const testDir = path12.join(screenshotsDir, safePwTestId);
|
|
5294
|
+
if (!fs9.existsSync(testDir))
|
|
5295
|
+
continue;
|
|
5296
|
+
for (const [safePwStepId, safeManifestStepId] of this._stepIdMap) {
|
|
5297
|
+
for (const suffix of ["-page.png", "-element.png"]) {
|
|
5298
|
+
const src = path12.join(testDir, `${safePwStepId}${suffix}`);
|
|
5299
|
+
if (fs9.existsSync(src))
|
|
5300
|
+
fs9.renameSync(src, path12.join(testDir, `${safeManifestStepId}${suffix}`));
|
|
5007
5301
|
}
|
|
5008
5302
|
}
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
fs9.
|
|
5016
|
-
|
|
5303
|
+
}
|
|
5304
|
+
for (const [safePwTestId, safeManifestTestId] of this._testIdMap) {
|
|
5305
|
+
const src = path12.join(screenshotsDir, safePwTestId);
|
|
5306
|
+
const dst = path12.join(screenshotsDir, safeManifestTestId);
|
|
5307
|
+
if (src !== dst && fs9.existsSync(src)) {
|
|
5308
|
+
if (fs9.existsSync(dst))
|
|
5309
|
+
fs9.rmSync(dst, { recursive: true });
|
|
5310
|
+
fs9.renameSync(src, dst);
|
|
5017
5311
|
}
|
|
5018
5312
|
}
|
|
5019
5313
|
const remapScreenshotPaths = (steps) => {
|
|
@@ -5031,7 +5325,7 @@ var SmoothDeployReporter = class {
|
|
|
5031
5325
|
if (!resolved)
|
|
5032
5326
|
continue;
|
|
5033
5327
|
remapScreenshotPaths(steps);
|
|
5034
|
-
const safeManifestTestId = resolved.manifestTest.id
|
|
5328
|
+
const safeManifestTestId = safeId(resolved.manifestTest.id);
|
|
5035
5329
|
const failurePath = path12.join(screenshotsDir, safeManifestTestId, "failure.png");
|
|
5036
5330
|
const failureScreenshot = fs9.existsSync(failurePath) ? `.smoothdeploy-output/screenshots/${safeManifestTestId}/failure.png` : null;
|
|
5037
5331
|
const key = resolved.manifestTest.id;
|
|
@@ -5040,15 +5334,8 @@ var SmoothDeployReporter = class {
|
|
|
5040
5334
|
manifest[key].push({ paramIndex: resolved.paramIndex, steps, failureScreenshot });
|
|
5041
5335
|
}
|
|
5042
5336
|
fs9.mkdirSync(outputDir, { recursive: true });
|
|
5043
|
-
fs9.writeFileSync(
|
|
5044
|
-
|
|
5045
|
-
JSON.stringify(manifest, null, 2)
|
|
5046
|
-
);
|
|
5047
|
-
this._emit({
|
|
5048
|
-
event: "runEnd",
|
|
5049
|
-
status: result.status,
|
|
5050
|
-
timestamp: Date.now()
|
|
5051
|
-
});
|
|
5337
|
+
fs9.writeFileSync(path12.join(outputDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
5338
|
+
this._emit({ event: "runEnd", status: result.status, timestamp: Date.now() });
|
|
5052
5339
|
}
|
|
5053
5340
|
_remapPath(screenshotPath) {
|
|
5054
5341
|
let result = screenshotPath;
|
|
@@ -5154,7 +5441,7 @@ function computeCommandHash(config2, runOptions) {
|
|
|
5154
5441
|
// packages/playwright/src/runner/tasks.ts
|
|
5155
5442
|
var import_fs11 = __toESM(require("fs"));
|
|
5156
5443
|
var import_path15 = __toESM(require("path"));
|
|
5157
|
-
var
|
|
5444
|
+
var import_util13 = require("util");
|
|
5158
5445
|
|
|
5159
5446
|
// packages/playwright/src/runner/rebase.ts
|
|
5160
5447
|
var import_fs9 = __toESM(require("fs"));
|
|
@@ -5308,7 +5595,7 @@ function applyPatchWithConflictMarkers(oldText, newText) {
|
|
|
5308
5595
|
// packages/playwright/src/runner/workerHost.ts
|
|
5309
5596
|
var import_fs10 = __toESM(require("fs"));
|
|
5310
5597
|
var import_path13 = __toESM(require("path"));
|
|
5311
|
-
var
|
|
5598
|
+
var import_common6 = require("../common");
|
|
5312
5599
|
|
|
5313
5600
|
// packages/playwright/src/isomorphic/folders.ts
|
|
5314
5601
|
function artifactsFolderName(workerIndex) {
|
|
@@ -5344,8 +5631,8 @@ var WorkerHost = class extends ProcessHost {
|
|
|
5344
5631
|
async start() {
|
|
5345
5632
|
await import_fs10.default.promises.mkdir(this._params.artifactsDir, { recursive: true });
|
|
5346
5633
|
return await this.startRunner(this._params, {
|
|
5347
|
-
onStdOut: (chunk) => this.emit("stdOut",
|
|
5348
|
-
onStdErr: (chunk) => this.emit("stdErr",
|
|
5634
|
+
onStdOut: (chunk) => this.emit("stdOut", import_common6.ipc.stdioChunkToParams(chunk)),
|
|
5635
|
+
onStdErr: (chunk) => this.emit("stdErr", import_common6.ipc.stdioChunkToParams(chunk))
|
|
5349
5636
|
});
|
|
5350
5637
|
}
|
|
5351
5638
|
async onExit() {
|
|
@@ -5377,16 +5664,17 @@ var WorkerHost = class extends ProcessHost {
|
|
|
5377
5664
|
};
|
|
5378
5665
|
|
|
5379
5666
|
// packages/playwright/src/runner/dispatcher.ts
|
|
5380
|
-
var
|
|
5381
|
-
var
|
|
5667
|
+
var import_common7 = require("../common");
|
|
5668
|
+
var import_util11 = require("../util");
|
|
5382
5669
|
var colors4 = require("playwright-core/lib/utilsBundle").colors;
|
|
5383
5670
|
var { ManualPromise: ManualPromise3 } = require("playwright-core/lib/coreBundle").iso;
|
|
5384
5671
|
var { eventsHelper } = require("playwright-core/lib/coreBundle").utils;
|
|
5385
5672
|
var Dispatcher = class {
|
|
5386
|
-
constructor(testRun) {
|
|
5673
|
+
constructor(testRun, options = {}) {
|
|
5387
5674
|
// Worker slot is claimed when it has jobDispatcher assigned.
|
|
5388
5675
|
this._workerSlots = [];
|
|
5389
5676
|
this._queue = [];
|
|
5677
|
+
this._isolatedJobs = /* @__PURE__ */ new Set();
|
|
5390
5678
|
this._workerLimitPerProjectId = /* @__PURE__ */ new Map();
|
|
5391
5679
|
this._queuedOrRunningHashCount = /* @__PURE__ */ new Map();
|
|
5392
5680
|
this._finished = new ManualPromise3();
|
|
@@ -5394,6 +5682,7 @@ var Dispatcher = class {
|
|
|
5394
5682
|
this._extraEnvByProjectId = /* @__PURE__ */ new Map();
|
|
5395
5683
|
this._producedEnvByProjectId = /* @__PURE__ */ new Map();
|
|
5396
5684
|
this._testRun = testRun;
|
|
5685
|
+
this._ignoreMaxFailures = !!options.ignoreMaxFailures;
|
|
5397
5686
|
for (const project of testRun.config.projects) {
|
|
5398
5687
|
if (project.workers)
|
|
5399
5688
|
this._workerLimitPerProjectId.set(project.id, project.workers);
|
|
@@ -5402,6 +5691,8 @@ var Dispatcher = class {
|
|
|
5402
5691
|
_findFirstJobToRun() {
|
|
5403
5692
|
for (let index = 0; index < this._queue.length; index++) {
|
|
5404
5693
|
const job = this._queue[index];
|
|
5694
|
+
if (this._isolatedJobs.has(job) && this._workerSlots.some((w) => !!w.jobDispatcher))
|
|
5695
|
+
continue;
|
|
5405
5696
|
const projectIdWorkerLimit = this._workerLimitPerProjectId.get(job.projectId);
|
|
5406
5697
|
if (!projectIdWorkerLimit)
|
|
5407
5698
|
return index;
|
|
@@ -5425,7 +5716,7 @@ var Dispatcher = class {
|
|
|
5425
5716
|
return;
|
|
5426
5717
|
}
|
|
5427
5718
|
this._queue.splice(jobIndex, 1);
|
|
5428
|
-
const jobDispatcher = new JobDispatcher(job, this._testRun, () => this.stop().catch(() => {
|
|
5719
|
+
const jobDispatcher = new JobDispatcher(job, this._testRun, this._ignoreMaxFailures ? void 0 : () => this.stop().catch(() => {
|
|
5429
5720
|
}));
|
|
5430
5721
|
this._workerSlots[workerIndex].jobDispatcher = jobDispatcher;
|
|
5431
5722
|
void this._runJobInWorker(workerIndex, jobDispatcher).then(() => {
|
|
@@ -5447,7 +5738,7 @@ var Dispatcher = class {
|
|
|
5447
5738
|
}
|
|
5448
5739
|
let startError;
|
|
5449
5740
|
if (!worker) {
|
|
5450
|
-
worker = this._createWorker(job, index,
|
|
5741
|
+
worker = this._createWorker(job, index, import_common7.ipc.serializeConfig(this._testRun.config, true));
|
|
5451
5742
|
this._workerSlots[index].worker = worker;
|
|
5452
5743
|
worker.on("exit", () => this._workerSlots[index].worker = void 0);
|
|
5453
5744
|
startError = await worker.start();
|
|
@@ -5467,9 +5758,16 @@ var Dispatcher = class {
|
|
|
5467
5758
|
);
|
|
5468
5759
|
else if (this._isWorkerRedundant(worker))
|
|
5469
5760
|
void worker.stop();
|
|
5470
|
-
if (!this._isStopped
|
|
5471
|
-
|
|
5472
|
-
|
|
5761
|
+
if (!this._isStopped) {
|
|
5762
|
+
if (result.remainingJob) {
|
|
5763
|
+
this._queue.unshift(result.remainingJob);
|
|
5764
|
+
this._updateCounterForWorkerHash(result.remainingJob.workerHash, 1);
|
|
5765
|
+
}
|
|
5766
|
+
if (result.isolatedRetriesJob) {
|
|
5767
|
+
this._isolatedJobs.add(result.isolatedRetriesJob);
|
|
5768
|
+
this._queue.push(result.isolatedRetriesJob);
|
|
5769
|
+
this._updateCounterForWorkerHash(result.isolatedRetriesJob.workerHash, 1);
|
|
5770
|
+
}
|
|
5473
5771
|
}
|
|
5474
5772
|
}
|
|
5475
5773
|
_checkFinished() {
|
|
@@ -5499,7 +5797,7 @@ var Dispatcher = class {
|
|
|
5499
5797
|
this._updateCounterForWorkerHash(group.workerHash, 1);
|
|
5500
5798
|
this._isStopped = false;
|
|
5501
5799
|
this._workerSlots = [];
|
|
5502
|
-
if (this._testRun.hasReachedMaxFailures())
|
|
5800
|
+
if (!this._ignoreMaxFailures && this._testRun.hasReachedMaxFailures())
|
|
5503
5801
|
void this.stop();
|
|
5504
5802
|
for (let i = 0; i < this._testRun.config.config.workers; i++)
|
|
5505
5803
|
this._workerSlots.push({});
|
|
@@ -5572,7 +5870,7 @@ var Dispatcher = class {
|
|
|
5572
5870
|
}
|
|
5573
5871
|
};
|
|
5574
5872
|
var JobDispatcher = class {
|
|
5575
|
-
constructor(job, testRun,
|
|
5873
|
+
constructor(job, testRun, onMaxFailuresReached) {
|
|
5576
5874
|
this.jobResult = new ManualPromise3();
|
|
5577
5875
|
this._listeners = [];
|
|
5578
5876
|
this._failedTests = /* @__PURE__ */ new Set();
|
|
@@ -5583,9 +5881,12 @@ var JobDispatcher = class {
|
|
|
5583
5881
|
this._workerIndex = 0;
|
|
5584
5882
|
this.job = job;
|
|
5585
5883
|
this._testRun = testRun;
|
|
5586
|
-
this.
|
|
5884
|
+
this._onMaxFailuresReached = onMaxFailuresReached;
|
|
5587
5885
|
this._remainingByTestId = new Map(this.job.tests.map((e) => [e.id, e]));
|
|
5588
5886
|
}
|
|
5887
|
+
_isStoppedByMaxFailures() {
|
|
5888
|
+
return !!this._onMaxFailuresReached && this._testRun.hasReachedMaxFailures();
|
|
5889
|
+
}
|
|
5589
5890
|
_onTestBegin(params) {
|
|
5590
5891
|
const test = this._remainingByTestId.get(params.testId);
|
|
5591
5892
|
if (!test) {
|
|
@@ -5600,7 +5901,7 @@ var JobDispatcher = class {
|
|
|
5600
5901
|
this._currentlyRunning = { test, result };
|
|
5601
5902
|
}
|
|
5602
5903
|
_onTestEnd(params) {
|
|
5603
|
-
if (this.
|
|
5904
|
+
if (this._isStoppedByMaxFailures()) {
|
|
5604
5905
|
params.status = "interrupted";
|
|
5605
5906
|
params.errors = [];
|
|
5606
5907
|
}
|
|
@@ -5655,7 +5956,9 @@ var JobDispatcher = class {
|
|
|
5655
5956
|
attachments: [],
|
|
5656
5957
|
annotations: [],
|
|
5657
5958
|
location: params.location,
|
|
5658
|
-
_stepId: params.stepId
|
|
5959
|
+
_stepId: params.stepId,
|
|
5960
|
+
_apiName: params.apiName,
|
|
5961
|
+
_channelMethod: params.channelMethod
|
|
5659
5962
|
};
|
|
5660
5963
|
steps.set(params.stepId, step);
|
|
5661
5964
|
(parentStep || result).steps.push(step);
|
|
@@ -5720,7 +6023,7 @@ var JobDispatcher = class {
|
|
|
5720
6023
|
for (const test of this._remainingByTestId.values()) {
|
|
5721
6024
|
if (!testIds.has(test.id))
|
|
5722
6025
|
continue;
|
|
5723
|
-
if (!this.
|
|
6026
|
+
if (!this._isStoppedByMaxFailures()) {
|
|
5724
6027
|
this._failTestWithErrors(test, errors);
|
|
5725
6028
|
errors = [];
|
|
5726
6029
|
}
|
|
@@ -5779,12 +6082,18 @@ var JobDispatcher = class {
|
|
|
5779
6082
|
serialSuite.allTests().forEach((test) => retryCandidates.add(test));
|
|
5780
6083
|
}
|
|
5781
6084
|
const remaining = [...this._remainingByTestId.values()];
|
|
6085
|
+
const isolatedRetries = [];
|
|
5782
6086
|
for (const test of retryCandidates) {
|
|
5783
|
-
if (test.results.length < test.retries + 1)
|
|
5784
|
-
|
|
6087
|
+
if (test.results.length < test.retries + 1) {
|
|
6088
|
+
if (this._testRun.config.retryStrategy === "immediate")
|
|
6089
|
+
remaining.push(test);
|
|
6090
|
+
else
|
|
6091
|
+
isolatedRetries.push(test);
|
|
6092
|
+
}
|
|
5785
6093
|
}
|
|
5786
|
-
const
|
|
5787
|
-
|
|
6094
|
+
const remainingJob = remaining.length ? { ...this.job, tests: remaining } : void 0;
|
|
6095
|
+
const isolatedRetriesJob = isolatedRetries.length ? { ...this.job, tests: isolatedRetries } : void 0;
|
|
6096
|
+
this._finished({ didFail: true, remainingJob, isolatedRetriesJob });
|
|
5788
6097
|
}
|
|
5789
6098
|
onExit(data) {
|
|
5790
6099
|
const unexpectedExitError = data.unexpectedly ? {
|
|
@@ -5802,7 +6111,7 @@ var JobDispatcher = class {
|
|
|
5802
6111
|
const runPayload = {
|
|
5803
6112
|
file: this.job.requireFile,
|
|
5804
6113
|
entries: this.job.tests.map((test) => {
|
|
5805
|
-
return { testId: test.id, retry: test.results.length };
|
|
6114
|
+
return { testId: test.id, retry: test.results.length, planAnnotations: test._planAnnotations };
|
|
5806
6115
|
})
|
|
5807
6116
|
};
|
|
5808
6117
|
worker.runTestGroup(runPayload);
|
|
@@ -5831,7 +6140,7 @@ var JobDispatcher = class {
|
|
|
5831
6140
|
addLocationAndSnippetToError(this._testRun.config.config, response.error);
|
|
5832
6141
|
return response;
|
|
5833
6142
|
} catch (e) {
|
|
5834
|
-
const error = (0,
|
|
6143
|
+
const error = (0, import_util11.serializeError)(e);
|
|
5835
6144
|
addLocationAndSnippetToError(this._testRun.config.config, error);
|
|
5836
6145
|
return { response: void 0, error };
|
|
5837
6146
|
}
|
|
@@ -5846,7 +6155,7 @@ var JobDispatcher = class {
|
|
|
5846
6155
|
}
|
|
5847
6156
|
skipWholeJob() {
|
|
5848
6157
|
const allTestsSkipped = this.job.tests.every((test) => test.expectedStatus === "skipped");
|
|
5849
|
-
if (allTestsSkipped && !this.
|
|
6158
|
+
if (allTestsSkipped && !this._isStoppedByMaxFailures()) {
|
|
5850
6159
|
for (const test of this.job.tests) {
|
|
5851
6160
|
const result = test._appendTestResult();
|
|
5852
6161
|
this._testRun.reporter.onTestBegin?.(test, result);
|
|
@@ -5863,11 +6172,11 @@ var JobDispatcher = class {
|
|
|
5863
6172
|
}
|
|
5864
6173
|
_reportTestEnd(test, result) {
|
|
5865
6174
|
this._testRun.reporter.onTestEnd?.(test, result);
|
|
5866
|
-
const hadMaxFailures = this.
|
|
6175
|
+
const hadMaxFailures = this._isStoppedByMaxFailures();
|
|
5867
6176
|
if (test.outcome() === "unexpected" && test.results.length > test.retries)
|
|
5868
6177
|
++this._testRun.failedTestCount;
|
|
5869
|
-
if (!hadMaxFailures && this.
|
|
5870
|
-
this.
|
|
6178
|
+
if (!hadMaxFailures && this._isStoppedByMaxFailures()) {
|
|
6179
|
+
this._onMaxFailuresReached?.();
|
|
5871
6180
|
this._testRun.reporter.onError?.({ message: colors4.red(`Testing stopped early after ${this._testRun.config.config.maxFailures} maximum allowed failures.`) });
|
|
5872
6181
|
}
|
|
5873
6182
|
}
|
|
@@ -5950,7 +6259,7 @@ var FixedNodeSIGINTHandler = class {
|
|
|
5950
6259
|
};
|
|
5951
6260
|
|
|
5952
6261
|
// packages/playwright/src/runner/taskRunner.ts
|
|
5953
|
-
var
|
|
6262
|
+
var import_util12 = require("../util");
|
|
5954
6263
|
var colors5 = require("playwright-core/lib/utilsBundle").colors;
|
|
5955
6264
|
var debug4 = require("playwright-core/lib/utilsBundle").debug;
|
|
5956
6265
|
var { ManualPromise: ManualPromise4 } = require("playwright-core/lib/coreBundle").iso;
|
|
@@ -5991,7 +6300,7 @@ var TaskRunner = class _TaskRunner {
|
|
|
5991
6300
|
await task.setup?.(context, errors, softErrors);
|
|
5992
6301
|
} catch (e) {
|
|
5993
6302
|
debug4("pw:test:task")(`error in "${task.title}": `, e);
|
|
5994
|
-
errors.push((0,
|
|
6303
|
+
errors.push((0, import_util12.serializeError)(e));
|
|
5995
6304
|
} finally {
|
|
5996
6305
|
for (const error of [...softErrors, ...errors])
|
|
5997
6306
|
this._reporter.onError?.(error);
|
|
@@ -6054,7 +6363,7 @@ var TimeoutWatcher = class {
|
|
|
6054
6363
|
// packages/playwright/src/runner/vcs.ts
|
|
6055
6364
|
var import_child_process2 = __toESM(require("child_process"));
|
|
6056
6365
|
var import_path14 = __toESM(require("path"));
|
|
6057
|
-
var
|
|
6366
|
+
var import_common8 = require("../common");
|
|
6058
6367
|
async function detectChangedTestFiles(baseCommit, configDir) {
|
|
6059
6368
|
function gitFileList(args) {
|
|
6060
6369
|
try {
|
|
@@ -6086,17 +6395,17 @@ async function detectChangedTestFiles(baseCommit, configDir) {
|
|
|
6086
6395
|
const untrackedFiles = gitFileList(["ls-files", "--others", "--exclude-standard"]).map((file) => import_path14.default.join(configDir, file));
|
|
6087
6396
|
const [gitRoot] = gitFileList(["rev-parse", "--show-toplevel"]);
|
|
6088
6397
|
const trackedFilesWithChanges = gitFileList(["diff", baseCommit, "--name-only"]).map((file) => import_path14.default.join(gitRoot, file));
|
|
6089
|
-
return new Set(
|
|
6398
|
+
return new Set(import_common8.cc.affectedTestFiles([...untrackedFiles, ...trackedFilesWithChanges]));
|
|
6090
6399
|
}
|
|
6091
6400
|
|
|
6092
6401
|
// packages/playwright/src/runner/tasks.ts
|
|
6093
|
-
var
|
|
6094
|
-
var
|
|
6402
|
+
var import_common9 = require("../common");
|
|
6403
|
+
var import_util14 = require("../util");
|
|
6095
6404
|
var debug5 = require("playwright-core/lib/utilsBundle").debug;
|
|
6096
6405
|
var { ManualPromise: ManualPromise5 } = require("playwright-core/lib/coreBundle").iso;
|
|
6097
6406
|
var { monotonicTime: monotonicTime6 } = require("playwright-core/lib/coreBundle").iso;
|
|
6098
6407
|
var { removeFolders: removeFolders4 } = require("playwright-core/lib/coreBundle").utils;
|
|
6099
|
-
var readDirAsync2 = (0,
|
|
6408
|
+
var readDirAsync2 = (0, import_util13.promisify)(import_fs11.default.readdir);
|
|
6100
6409
|
var TestRun = class {
|
|
6101
6410
|
constructor(config2, reporter, options) {
|
|
6102
6411
|
this.rootSuite = void 0;
|
|
@@ -6124,7 +6433,7 @@ var TestRun = class {
|
|
|
6124
6433
|
result() {
|
|
6125
6434
|
const hasFailedTests = this.rootSuite?.allTests().some((test) => !test.ok());
|
|
6126
6435
|
const hasFlakyTests = this.rootSuite?.allTests().some((test) => test.outcome() === "flaky");
|
|
6127
|
-
return this.hasWorkerErrors || this.hasReachedMaxFailures() || hasFailedTests || this.config.config.failOnFlakyTests && hasFlakyTests ? "failed" : "passed";
|
|
6436
|
+
return this.hasWorkerErrors || this.reporter.hasReporterErrors() || this.hasReachedMaxFailures() || hasFailedTests || this.config.config.failOnFlakyTests && hasFlakyTests ? "failed" : "passed";
|
|
6128
6437
|
}
|
|
6129
6438
|
};
|
|
6130
6439
|
async function runTasks(testRun, tasks, globalTimeout, cancelPromise) {
|
|
@@ -6151,6 +6460,8 @@ async function finishTaskRun(testRun, status) {
|
|
|
6151
6460
|
if (modifiedResult && modifiedResult.status)
|
|
6152
6461
|
status = modifiedResult.status;
|
|
6153
6462
|
await testRun.reporter.onExit();
|
|
6463
|
+
if (status === "passed" && testRun.reporter.hasReporterErrors())
|
|
6464
|
+
status = "failed";
|
|
6154
6465
|
return status;
|
|
6155
6466
|
}
|
|
6156
6467
|
function createGlobalSetupTasks(config2) {
|
|
@@ -6173,7 +6484,7 @@ function createClearCacheTask(config2) {
|
|
|
6173
6484
|
return {
|
|
6174
6485
|
title: "clear cache",
|
|
6175
6486
|
setup: async () => {
|
|
6176
|
-
await (0,
|
|
6487
|
+
await (0, import_util14.removeDirAndLogToConsole)(import_common9.cc.cacheDir);
|
|
6177
6488
|
for (const plugin of config2.plugins)
|
|
6178
6489
|
await plugin.instance?.clearCache?.();
|
|
6179
6490
|
}
|
|
@@ -6272,12 +6583,12 @@ function createListFilesTask() {
|
|
|
6272
6583
|
await createRootSuite(testRun, errors, false);
|
|
6273
6584
|
await collectProjectsAndTestFiles(testRun, false);
|
|
6274
6585
|
for (const [project, files] of testRun.projectFiles) {
|
|
6275
|
-
const projectSuite = new
|
|
6586
|
+
const projectSuite = new import_common9.test.Suite(project.project.name, "project");
|
|
6276
6587
|
projectSuite._fullProject = project;
|
|
6277
6588
|
testRun.rootSuite._addSuite(projectSuite);
|
|
6278
6589
|
const suites = files.map((file) => {
|
|
6279
6590
|
const title = import_path15.default.relative(testRun.config.config.rootDir, file);
|
|
6280
|
-
const suite = new
|
|
6591
|
+
const suite = new import_common9.test.Suite(title, "file");
|
|
6281
6592
|
suite.location = { file, line: 0, column: 0 };
|
|
6282
6593
|
projectSuite._addSuite(suite);
|
|
6283
6594
|
return suite;
|
|
@@ -6292,7 +6603,7 @@ function createLoadTask(mode, options) {
|
|
|
6292
6603
|
title: "load tests",
|
|
6293
6604
|
setup: async (testRun, errors, softErrors) => {
|
|
6294
6605
|
if (testRun.options.locations?.length) {
|
|
6295
|
-
const { testFilter, fileFilter } =
|
|
6606
|
+
const { testFilter, fileFilter } = import_common9.suiteUtils.createFiltersFromArguments(testRun.options.locations);
|
|
6296
6607
|
testRun.loadFileFilters.push(fileFilter);
|
|
6297
6608
|
testRun.preOnlyTestFilters.push(testFilter);
|
|
6298
6609
|
}
|
|
@@ -6306,14 +6617,14 @@ function createLoadTask(mode, options) {
|
|
|
6306
6617
|
testRun.preOnlyTestFilters.push((test) => !testFilter(test));
|
|
6307
6618
|
}
|
|
6308
6619
|
if (testRun.options.grep || testRun.options.grepInvert) {
|
|
6309
|
-
const grepMatcher = testRun.options.grep ? (0,
|
|
6310
|
-
const grepInvertMatcher = testRun.options.grepInvert ? (0,
|
|
6620
|
+
const grepMatcher = testRun.options.grep ? (0, import_util14.createTitleMatcher)((0, import_util14.forceRegExp)(testRun.options.grep)) : () => true;
|
|
6621
|
+
const grepInvertMatcher = testRun.options.grepInvert ? (0, import_util14.createTitleMatcher)((0, import_util14.forceRegExp)(testRun.options.grepInvert)) : () => false;
|
|
6311
6622
|
testRun.preOnlyTestFilters.push((test) => {
|
|
6312
6623
|
const grepTitle = test._grepTitleWithTags();
|
|
6313
6624
|
return !grepInvertMatcher(grepTitle) && grepMatcher(grepTitle);
|
|
6314
6625
|
});
|
|
6315
6626
|
}
|
|
6316
|
-
if (testRun.options.lastFailedTestIds
|
|
6627
|
+
if (testRun.options.lastFailedTestIds) {
|
|
6317
6628
|
const failedTestIds = new Set(testRun.options.lastFailedTestIds);
|
|
6318
6629
|
testRun.postShardTestFilters.push((test) => failedTestIds.has(test.id));
|
|
6319
6630
|
}
|
|
@@ -6361,6 +6672,7 @@ function createPhasesTask() {
|
|
|
6361
6672
|
const projectToSuite = new Map(testRun.rootSuite.suites.map((suite) => [suite._fullProject, suite]));
|
|
6362
6673
|
const allProjects = [...projectToSuite.keys()];
|
|
6363
6674
|
const teardownToSetups = buildTeardownToSetupsMap(allProjects);
|
|
6675
|
+
const ignoreMaxFailuresProjectIds = new Set(testRun.config.config.maxFailures > 0 ? [...teardownToSetups.keys()].map((project) => project.id) : []);
|
|
6364
6676
|
const teardownToSetupsDependents = /* @__PURE__ */ new Map();
|
|
6365
6677
|
for (const [teardown, setups] of teardownToSetups) {
|
|
6366
6678
|
const closure = buildDependentProjects(setups, allProjects);
|
|
@@ -6379,11 +6691,14 @@ function createPhasesTask() {
|
|
|
6379
6691
|
}
|
|
6380
6692
|
for (const project of phaseProjects)
|
|
6381
6693
|
processed.add(project);
|
|
6382
|
-
|
|
6694
|
+
for (const ignoreMaxFailures of [false, true]) {
|
|
6695
|
+
const projects = phaseProjects.filter((project) => ignoreMaxFailuresProjectIds.has(project.id) === ignoreMaxFailures);
|
|
6696
|
+
if (!projects.length)
|
|
6697
|
+
continue;
|
|
6383
6698
|
let testGroupsInPhase = 0;
|
|
6384
|
-
const phase = { dispatcher: new Dispatcher(testRun), projects: [] };
|
|
6699
|
+
const phase = { dispatcher: new Dispatcher(testRun, { ignoreMaxFailures }), projects: [] };
|
|
6385
6700
|
testRun.phases.push(phase);
|
|
6386
|
-
for (const project of
|
|
6701
|
+
for (const project of projects) {
|
|
6387
6702
|
const projectSuite = projectToSuite.get(project);
|
|
6388
6703
|
const testGroups = createTestGroups(projectSuite, testRun.config.config.workers);
|
|
6389
6704
|
phase.projects.push({ project, projectSuite, testGroups });
|
|
@@ -6458,12 +6773,12 @@ var LastRunReporter = class {
|
|
|
6458
6773
|
}
|
|
6459
6774
|
async filterLastFailed() {
|
|
6460
6775
|
if (!this._lastRunFile)
|
|
6461
|
-
return
|
|
6776
|
+
return void 0;
|
|
6462
6777
|
try {
|
|
6463
6778
|
const lastRunInfo = JSON.parse(await import_fs12.default.promises.readFile(this._lastRunFile, "utf8"));
|
|
6464
6779
|
return lastRunInfo.failedTests;
|
|
6465
6780
|
} catch {
|
|
6466
|
-
return
|
|
6781
|
+
return void 0;
|
|
6467
6782
|
}
|
|
6468
6783
|
}
|
|
6469
6784
|
version() {
|
|
@@ -6509,7 +6824,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6509
6824
|
this._configCLIOverrides = configCLIOverrides;
|
|
6510
6825
|
this._watcher = new FSWatcher((events) => {
|
|
6511
6826
|
const collector = /* @__PURE__ */ new Set();
|
|
6512
|
-
events.forEach((f) =>
|
|
6827
|
+
events.forEach((f) => import_common10.cc.collectAffectedTestFiles(f.file, collector));
|
|
6513
6828
|
this.emit(TestRunnerEvent.TestFilesChanged, [...collector]);
|
|
6514
6829
|
});
|
|
6515
6830
|
}
|
|
@@ -6719,7 +7034,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6719
7034
|
this._watchedTestDependencies = /* @__PURE__ */ new Set();
|
|
6720
7035
|
for (const fileName of fileNames) {
|
|
6721
7036
|
this._watchedTestDependencies.add(fileName);
|
|
6722
|
-
|
|
7037
|
+
import_common10.cc.dependenciesForTestFile(fileName).forEach((file) => this._watchedTestDependencies.add(file));
|
|
6723
7038
|
}
|
|
6724
7039
|
await this._updateWatcher(true);
|
|
6725
7040
|
}
|
|
@@ -6735,7 +7050,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6735
7050
|
]);
|
|
6736
7051
|
if (status !== "passed")
|
|
6737
7052
|
return { errors: errorReporter.errors(), testFiles: [] };
|
|
6738
|
-
return { testFiles:
|
|
7053
|
+
return { testFiles: import_common10.cc.affectedTestFiles(files) };
|
|
6739
7054
|
}
|
|
6740
7055
|
async stopTests() {
|
|
6741
7056
|
this._testRun?.stop?.resolve();
|
|
@@ -6749,7 +7064,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6749
7064
|
}
|
|
6750
7065
|
async _loadConfig(overrides) {
|
|
6751
7066
|
try {
|
|
6752
|
-
const config2 = await
|
|
7067
|
+
const config2 = await import_common10.configLoader.loadConfig(this.configLocation, overrides);
|
|
6753
7068
|
if (!this._plugins) {
|
|
6754
7069
|
webServerPluginsForConfig(config2).forEach((p) => config2.plugins.push({ factory: p }));
|
|
6755
7070
|
addGitCommitInfoPlugin(config2);
|
|
@@ -6760,7 +7075,7 @@ var TestRunner = class extends import_events2.default {
|
|
|
6760
7075
|
this._lastLoadedConfig = config2;
|
|
6761
7076
|
return { config: config2 };
|
|
6762
7077
|
} catch (e) {
|
|
6763
|
-
return { config: null, error: (0,
|
|
7078
|
+
return { config: null, error: (0, import_util15.serializeError)(e) };
|
|
6764
7079
|
}
|
|
6765
7080
|
}
|
|
6766
7081
|
lastLoadedConfig() {
|
|
@@ -6801,7 +7116,7 @@ async function runAllTestsWithConfig(config2, options) {
|
|
|
6801
7116
|
const lastRun = new LastRunReporter(filteredProjects, options.listMode, options.lastFailedFile);
|
|
6802
7117
|
if (options.lastFailed) {
|
|
6803
7118
|
const lastFailedTestIds = await lastRun.filterLastFailed();
|
|
6804
|
-
if (lastFailedTestIds
|
|
7119
|
+
if (lastFailedTestIds)
|
|
6805
7120
|
options = { ...options, lastFailedTestIds };
|
|
6806
7121
|
}
|
|
6807
7122
|
const reporter = new InternalReporter([...reporters, lastRun]);
|
|
@@ -6828,9 +7143,9 @@ __export(testServer_exports, {
|
|
|
6828
7143
|
runTestServer: () => runTestServer,
|
|
6829
7144
|
runUIMode: () => runUIMode
|
|
6830
7145
|
});
|
|
6831
|
-
var
|
|
7146
|
+
var import_util16 = __toESM(require("util"));
|
|
6832
7147
|
var import_coreBundle3 = require("playwright-core/lib/coreBundle");
|
|
6833
|
-
var
|
|
7148
|
+
var import_common11 = require("../common");
|
|
6834
7149
|
|
|
6835
7150
|
// packages/playwright/src/runner/uiModeReporter.ts
|
|
6836
7151
|
var UIModeReporter = class extends TeleReporterEmitter {
|
|
@@ -6988,7 +7303,7 @@ var TestServerDispatcher = class {
|
|
|
6988
7303
|
if (interceptStdio) {
|
|
6989
7304
|
if (debug6.log === originalDebugLog) {
|
|
6990
7305
|
debug6.log = (...args) => {
|
|
6991
|
-
const string =
|
|
7306
|
+
const string = import_util16.default.format(...args) + "\n";
|
|
6992
7307
|
return originalStderrWrite.apply(process.stderr, [string]);
|
|
6993
7308
|
};
|
|
6994
7309
|
}
|
|
@@ -7012,7 +7327,7 @@ var TestServerDispatcher = class {
|
|
|
7012
7327
|
}
|
|
7013
7328
|
};
|
|
7014
7329
|
async function runUIMode(configFile, configCLIOverrides, options) {
|
|
7015
|
-
const configLocation =
|
|
7330
|
+
const configLocation = import_common11.configLoader.resolveConfigLocation(configFile);
|
|
7016
7331
|
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server, cancelPromise) => {
|
|
7017
7332
|
await import_coreBundle3.server.installRootRedirect(server, void 0, { ...options, webApp: "uiMode.html" });
|
|
7018
7333
|
if (options.host !== void 0 || options.port !== void 0) {
|
|
@@ -7031,7 +7346,7 @@ async function runUIMode(configFile, configCLIOverrides, options) {
|
|
|
7031
7346
|
});
|
|
7032
7347
|
}
|
|
7033
7348
|
async function installedChromiumChannelForUI(configLocation, configCLIOverrides) {
|
|
7034
|
-
const config2 = await
|
|
7349
|
+
const config2 = await import_common11.configLoader.loadConfig(configLocation, configCLIOverrides).catch((e) => null);
|
|
7035
7350
|
if (!config2)
|
|
7036
7351
|
return void 0;
|
|
7037
7352
|
if (config2.projects.some((p) => (!p.project.use.browserName || p.project.use.browserName === "chromium") && !p.project.use.channel))
|
|
@@ -7043,7 +7358,7 @@ async function installedChromiumChannelForUI(configLocation, configCLIOverrides)
|
|
|
7043
7358
|
return void 0;
|
|
7044
7359
|
}
|
|
7045
7360
|
async function runTestServer(configFile, configCLIOverrides, options) {
|
|
7046
|
-
const configLocation =
|
|
7361
|
+
const configLocation = import_common11.configLoader.resolveConfigLocation(configFile);
|
|
7047
7362
|
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server) => {
|
|
7048
7363
|
console.log("Listening on " + server.urlPrefix("precise").replace("http:", "ws:") + "/" + server.wsGuid());
|
|
7049
7364
|
});
|
|
@@ -7087,7 +7402,7 @@ var import_events3 = require("events");
|
|
|
7087
7402
|
var import_coreBundle4 = require("playwright-core/lib/coreBundle");
|
|
7088
7403
|
|
|
7089
7404
|
// packages/playwright/src/isomorphic/testTree.ts
|
|
7090
|
-
var statusEx = Symbol("statusEx");
|
|
7405
|
+
var statusEx = /* @__PURE__ */ Symbol("statusEx");
|
|
7091
7406
|
|
|
7092
7407
|
// packages/playwright/src/isomorphic/teleSuiteUpdater.ts
|
|
7093
7408
|
var TeleSuiteUpdater = class {
|
|
@@ -7830,7 +8145,7 @@ var JsonStringInternalizer = class {
|
|
|
7830
8145
|
};
|
|
7831
8146
|
|
|
7832
8147
|
// packages/playwright/src/reporters/merge.ts
|
|
7833
|
-
var
|
|
8148
|
+
var import_util17 = require("../util");
|
|
7834
8149
|
var { isPathInside } = require("playwright-core/lib/coreBundle").utils;
|
|
7835
8150
|
var { ZipFile } = require("playwright-core/lib/coreBundle").utils;
|
|
7836
8151
|
async function createMergedReport(config2, dir, reporterDescriptions, rootDirOverride) {
|
|
@@ -7895,6 +8210,7 @@ async function createMergedReport(config2, dir, reporterDescriptions, rootDirOve
|
|
|
7895
8210
|
});
|
|
7896
8211
|
}
|
|
7897
8212
|
await dispatchEvents(eventData.epilogue);
|
|
8213
|
+
return multiplexer.hasReporterErrors() ? "failed" : "passed";
|
|
7898
8214
|
}
|
|
7899
8215
|
var commonEventNames = ["onBlobReportMetadata", "onConfigure", "onProject", "onBegin", "onEnd"];
|
|
7900
8216
|
var commonEvents = new Set(commonEventNames);
|
|
@@ -7925,7 +8241,7 @@ async function extractAndParseReports(dir, shardFiles, internalizer, printStatus
|
|
|
7925
8241
|
const reportNames = new UniqueFileNameGenerator();
|
|
7926
8242
|
for (const file of shardFiles) {
|
|
7927
8243
|
const absolutePath = import_path19.default.join(dir, file);
|
|
7928
|
-
printStatus(`extracting: ${(0,
|
|
8244
|
+
printStatus(`extracting: ${(0, import_util17.relativeFilePath)(absolutePath)}`);
|
|
7929
8245
|
const zipFile = new ZipFile(absolutePath);
|
|
7930
8246
|
const entryNames = await zipFile.entries();
|
|
7931
8247
|
for (const entryName of entryNames.sort()) {
|