@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.
@@ -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 import_common9 = require("../common");
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").iso;
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
- _write(chunk, encoding, callback) {
1028
- this._target.write((0, import_util2.stripAnsiEscapes)(chunk.toString()), callback);
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, import_path2.default.sep, !!process.env.PWDEBUGIMPL);
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
- wrap(() => reporter.onConfigure?.(config2));
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
- wrap(() => reporter.onBegin?.(suite));
1596
+ this._wrap(() => reporter.onBegin?.(suite));
1563
1597
  }
1564
1598
  onTestBegin(test, result) {
1565
1599
  for (const reporter of this._reporters)
1566
- wrap(() => reporter.onTestBegin?.(test, result));
1600
+ this._wrap(() => reporter.onTestBegin?.(test, result));
1567
1601
  }
1568
1602
  onStdOut(chunk, test, result) {
1569
1603
  for (const reporter of this._reporters)
1570
- wrap(() => reporter.onStdOut?.(chunk, test, result));
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
- wrap(() => reporter.onStdErr?.(chunk, test, result));
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 wrapAsync(() => reporter.onTestPaused?.(test, result));
1612
+ await this._wrapAsync(() => reporter.onTestPaused?.(test, result));
1579
1613
  }
1580
1614
  onTestEnd(test, result) {
1581
1615
  for (const reporter of this._reporters)
1582
- wrap(() => reporter.onTestEnd?.(test, result));
1616
+ this._wrap(() => reporter.onTestEnd?.(test, result));
1583
1617
  }
1584
1618
  onReportConfigure(params) {
1585
1619
  for (const reporter of this._reporters)
1586
- wrap(() => reporter.onReportConfigure?.(params));
1620
+ this._wrap(() => reporter.onReportConfigure?.(params));
1587
1621
  }
1588
1622
  onReportEnd(params) {
1589
1623
  for (const reporter of this._reporters)
1590
- wrap(() => reporter.onReportEnd?.(params));
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 wrapAsync(() => reporter.onEnd?.(result));
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 wrapAsync(() => reporter.onExit?.());
1636
+ await this._wrapAsync(() => reporter.onExit?.());
1603
1637
  }
1604
1638
  onError(error, workerInfo) {
1605
1639
  for (const reporter of this._reporters)
1606
- wrap(() => reporter.onError?.(error, workerInfo));
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
- wrap(() => reporter.onStepBegin?.(test, result, step));
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
- wrap(() => reporter.onStepEnd?.(test, result, step));
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
- wrap(() => prints = r.printsToStdio ? r.printsToStdio() : true);
1653
+ this._wrap(() => prints = r.printsToStdio ? r.printsToStdio() : true, false);
1620
1654
  return prints;
1621
1655
  });
1622
1656
  }
1623
- };
1624
- async function wrapAsync(callback) {
1625
- try {
1626
- return await callback();
1627
- } catch (e) {
1628
- console.error("Error in reporter", e);
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
- function wrap(callback) {
1632
- try {
1633
- callback();
1634
- } catch (e) {
1635
- console.error("Error in reporter", e);
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 ? this._reporter.printsToStdio() : true;
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 import_util14 = require("../util");
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 import_util5 = require("../util");
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 import_util3 = require("util");
2058
- var import_util4 = require("../util");
2059
- var minimatch = require("playwright-core/lib/utilsBundle").minimatch;
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, import_util3.promisify)(import_fs2.default.readFile);
2062
- var readDirAsync = (0, import_util3.promisify)(import_fs2.default.readdir);
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, import_util4.createFileMatcher)(project.project.testMatch);
2168
- const testIgnore = (0, import_util4.createFileMatcher)(project.project.testIgnore);
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 import_common3 = require("../common");
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 import_common3.cc.dependenciesForTestFile(file)) {
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 import_common3.test.Suite("", "root");
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 import_common3.test.Suite("", "root");
2537
+ const filteredRoot = new import_common4.test.Suite("", "root");
2433
2538
  for (const filteredProjectSuite of filteredProjectSuites.values())
2434
2539
  filteredRoot._addSuite(filteredProjectSuite);
2435
- import_common3.suiteUtils.filterOnly(filteredRoot);
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
- if (config2.config.shard) {
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
- import_common3.suiteUtils.filterTestsRemoveEmptySuites(rootSuite, (test) => testsInThisShard.has(test));
2589
+ import_common4.suiteUtils.filterTestsRemoveEmptySuites(rootSuite, (test) => testsInThisShard.has(test));
2468
2590
  }
2469
2591
  if (testRun.postShardTestFilters.length)
2470
- import_common3.suiteUtils.filterTestsRemoveEmptySuites(rootSuite, (test) => testRun.postShardTestFilters.every((filter) => filter(test)));
2592
+ import_common4.suiteUtils.filterTestsRemoveEmptySuites(rootSuite, (test) => testRun.postShardTestFilters.every((filter) => filter(test)));
2471
2593
  const topLevelProjects = [];
2472
2594
  {
2473
- const projectClosure2 = new Map(buildProjectsClosure(rootSuite.suites.map((suite) => suite._fullProject)));
2474
- for (const [project, level] of projectClosure2.entries()) {
2475
- if (level === "dependency")
2476
- rootSuite._prependSuite(buildProjectSuite(project, projectSuites.get(project)));
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 import_common3.test.Suite(project.project.name, "project");
2608
+ const projectSuite = new import_common4.test.Suite(project.project.name, "project");
2486
2609
  for (const fileSuite of fileSuites)
2487
- projectSuite._addSuite(import_common3.suiteUtils.bindFileSuiteToProject(project, fileSuite));
2488
- const grepMatcher = (0, import_util5.createTitleMatcher)(project.project.grep);
2489
- const grepInvertMatcher = project.project.grepInvert ? (0, import_util5.createTitleMatcher)(project.project.grepInvert) : null;
2490
- import_common3.suiteUtils.filterTestsRemoveEmptySuites(projectSuite, (test) => {
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
- import_common3.suiteUtils.filterTestsRemoveEmptySuites(result, (test) => testFilters.every((filter) => filter(test)));
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 import_common3.test.Suite(project.project.name, "project");
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
- import_common3.suiteUtils.applyRepeatEachIndex(project, clone, repeatEachIndex);
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 import_common3.transform.requireOrImport(file);
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, import_util5.errorWithFile)(file, `file must export a single ${expectConstructor ? "class" : "function"}.`);
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, import_util5.parseLocationArg)(tokens[0]).file), titlePath: tokens.slice(1) };
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, import_util5.errorWithFile)(filePath, "Cannot read test list file: " + e.message);
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 import_util6 = require("../util");
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, import_util6.stripAnsiEscapes)(`::${type} ${configs}::${message}
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 import_util7 = require("../util");
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, import_util7.resolveReporterOutputPath)("playwright-report", this._options.configDir, this._options.outputFolder);
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, import_util7.resolveReporterOutputPath)("playwright-report", process.cwd(), void 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, import_util7.stripAnsiEscapes)(a.body);
3753
+ lastAttachment.body += (0, import_util8.stripAnsiEscapes)(a.body);
3625
3754
  return null;
3626
3755
  }
3627
- a.body = (0, import_util7.stripAnsiEscapes)(a.body);
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, import_util7.stripAnsiEscapes)(message).split("\n")[0] || void 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 import_common4 = require("../common");
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: import_common4.config.getProjectId(project),
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 = import_common4.config.getProjectId(projectSuite.project());
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 import_util8 = require("../util");
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, import_util8.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test))
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, import_util8.stripAnsiEscapes)(formatFailure(nonTerminalScreen, this.config, test))
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, import_util8.stripAnsiEscapes)(stackTrace) });
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, import_util8.stripAnsiEscapes)(error.message || error.value || "");
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, import_util8.stripAnsiEscapes)(text);
4491
+ text = (0, import_util9.stripAnsiEscapes)(text);
4363
4492
  if (isCharacterData) {
4364
4493
  text = "<![CDATA[" + text.replace(/]]>/g, "]]&gt;") + "]]>";
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 import_util9 = require("../util");
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, import_util9.stripAnsiEscapes)(statusMark).length;
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
- // Map pw TestStep → matched manifest step
4772
- this._stepToManifest = /* @__PURE__ */ new WeakMap();
4773
- // Child counter per parent (TestStep for nested, test.id string for root-level)
4774
- this._childCounters = /* @__PURE__ */ new Map();
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 (!fs9.existsSync(manifestPath))
4798
- throw new Error(`SmoothDeploy reporter requires .smoothdeploy-manifest.json in ${this._configDir}`);
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
- process.stdout.write(`[SMOOTHDEPLOY_EVENT]${JSON.stringify(event)}
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
- _isUserStep(step) {
4807
- const title = step.title;
4808
- if (title === "Before Hooks" || title === "After Hooks" || title === "Worker Cleanup")
4809
- return false;
4810
- if (title.startsWith('Fixture "'))
4811
- return false;
4812
- const internalSteps = [
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 === testTitle);
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 = testTitle.slice(mt.title.length);
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
- const safePw = test.id.replace(/[^a-zA-Z0-9_-]/g, "-");
4871
- const safeManifest = resolved.manifestTest.id.replace(/[^a-zA-Z0-9_-]/g, "-");
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._childCounters.delete(test.id);
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 (!this._isUserStep(step))
5187
+ if (!isUserStep(step))
4900
5188
  return;
4901
5189
  const resolved = this._resolvedTests.get(test.id);
4902
5190
  if (!resolved)
4903
5191
  return;
4904
- let parentStep = step.parent;
4905
- while (parentStep && !this._stepToOutput.has(parentStep))
4906
- parentStep = parentStep.parent;
4907
- const parentKey = parentStep ?? test.id;
4908
- const parentManifest = parentStep ? this._stepToManifest.get(parentStep) : void 0;
4909
- const parentSteps = parentManifest ? parentManifest.children : resolved.manifestTest.steps;
4910
- const idx = this._childCounters.get(parentKey) ?? 0;
4911
- this._childCounters.set(parentKey, idx + 1);
4912
- const manifestStep = parentSteps?.[idx] ?? null;
4913
- if (manifestStep)
4914
- this._stepToManifest.set(step, manifestStep);
4915
- this._childCounters.set(step, 0);
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._stepToOutput.set(step, outputStep);
4927
- const parentOutput = parentStep ? this._stepToOutput.get(parentStep) : void 0;
4928
- if (parentOutput)
4929
- parentOutput.children.push(outputStep);
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(outputStep);
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?.id,
4937
- action: manifestStep?.action,
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 (!this._isUserStep(step))
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 manifestStep = this._stepToManifest.get(step) ?? null;
4950
- const outputStep = this._stepToOutput.get(step);
4951
- const safeTestId = test.id.replace(/[^a-zA-Z0-9_-]/g, "-");
4952
- const noScreenshotPrefixes = [
4953
- "Navigate",
4954
- "Go back",
4955
- "Go forward",
4956
- "Reload",
4957
- "Screenshot",
4958
- "Wait for",
4959
- "Pause",
4960
- "Evaluate"
4961
- ];
4962
- const hasScreenshot = step.category === "pw:api" && !noScreenshotPrefixes.some((prefix) => step.title.startsWith(prefix));
4963
- const internalStepId = step._stepId ?? step.title;
4964
- const safeStepId = internalStepId.replace(/[^a-zA-Z0-9_-]/g, "-");
4965
- const screenshots = hasScreenshot ? {
4966
- page: `.smoothdeploy-output/screenshots/${safeTestId}/${safeStepId}-page.png`,
4967
- element: `.smoothdeploy-output/screenshots/${safeTestId}/${safeStepId}-element.png`
4968
- } : null;
4969
- if (manifestStep) {
4970
- const safeManifestStepId = manifestStep.id.replace(/[^a-zA-Z0-9_-]/g, "-");
4971
- this._stepIdMap.set(safeStepId, safeManifestStepId);
4972
- }
4973
- if (outputStep) {
4974
- outputStep.duration = step.duration;
4975
- const hasDescendantError = (steps) => steps.some((c) => c.error !== null || hasDescendantError(c.children));
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: manifestStep?.id,
4985
- action: manifestStep?.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
- if (this._manifest) {
4996
- for (const [safePwTestId] of this._testIdMap) {
4997
- const testDir = path12.join(screenshotsDir, safePwTestId);
4998
- if (!fs9.existsSync(testDir))
4999
- continue;
5000
- for (const [safePwStepId, safeManifestStepId] of this._stepIdMap) {
5001
- for (const suffix of ["-page.png", "-element.png"]) {
5002
- const src = path12.join(testDir, `${safePwStepId}${suffix}`);
5003
- const dst = path12.join(testDir, `${safeManifestStepId}${suffix}`);
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
- for (const [safePwTestId, safeManifestTestId] of this._testIdMap) {
5010
- const src = path12.join(screenshotsDir, safePwTestId);
5011
- const dst = path12.join(screenshotsDir, safeManifestTestId);
5012
- if (fs9.existsSync(src)) {
5013
- if (fs9.existsSync(dst))
5014
- fs9.rmSync(dst, { recursive: true });
5015
- fs9.renameSync(src, dst);
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.replace(/[^a-zA-Z0-9_-]/g, "-");
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
- path12.join(outputDir, "manifest.json"),
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 import_util12 = require("util");
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 import_common5 = require("../common");
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", import_common5.ipc.stdioChunkToParams(chunk)),
5348
- onStdErr: (chunk) => this.emit("stdErr", import_common5.ipc.stdioChunkToParams(chunk))
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 import_common6 = require("../common");
5381
- var import_util10 = require("../util");
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, import_common6.ipc.serializeConfig(this._testRun.config, true));
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 && result.newJob) {
5471
- this._queue.unshift(result.newJob);
5472
- this._updateCounterForWorkerHash(result.newJob.workerHash, 1);
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, stopCallback) {
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._stopCallback = stopCallback;
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._testRun.hasReachedMaxFailures()) {
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._testRun.hasReachedMaxFailures()) {
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
- remaining.push(test);
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 newJob = remaining.length ? { ...this.job, tests: remaining } : void 0;
5787
- this._finished({ didFail: true, newJob });
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, import_util10.serializeError)(e);
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._testRun.hasReachedMaxFailures()) {
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._testRun.hasReachedMaxFailures();
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._testRun.hasReachedMaxFailures()) {
5870
- this._stopCallback();
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 import_util11 = require("../util");
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, import_util11.serializeError)(e));
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 import_common7 = require("../common");
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(import_common7.cc.affectedTestFiles([...untrackedFiles, ...trackedFilesWithChanges]));
6398
+ return new Set(import_common8.cc.affectedTestFiles([...untrackedFiles, ...trackedFilesWithChanges]));
6090
6399
  }
6091
6400
 
6092
6401
  // packages/playwright/src/runner/tasks.ts
6093
- var import_common8 = require("../common");
6094
- var import_util13 = require("../util");
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, import_util12.promisify)(import_fs11.default.readdir);
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, import_util13.removeDirAndLogToConsole)(import_common8.cc.cacheDir);
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 import_common8.test.Suite(project.project.name, "project");
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 import_common8.test.Suite(title, "file");
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 } = import_common8.suiteUtils.createFiltersFromArguments(testRun.options.locations);
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, import_util13.createTitleMatcher)((0, import_util13.forceRegExp)(testRun.options.grep)) : () => true;
6310
- const grepInvertMatcher = testRun.options.grepInvert ? (0, import_util13.createTitleMatcher)((0, import_util13.forceRegExp)(testRun.options.grepInvert)) : () => false;
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?.length) {
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
- if (phaseProjects.length) {
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 phaseProjects) {
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) => import_common9.cc.collectAffectedTestFiles(f.file, collector));
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
- import_common9.cc.dependenciesForTestFile(fileName).forEach((file) => this._watchedTestDependencies.add(file));
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: import_common9.cc.affectedTestFiles(files) };
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 import_common9.configLoader.loadConfig(this.configLocation, overrides);
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, import_util14.serializeError)(e) };
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.length)
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 import_util15 = __toESM(require("util"));
7146
+ var import_util16 = __toESM(require("util"));
6832
7147
  var import_coreBundle3 = require("playwright-core/lib/coreBundle");
6833
- var import_common10 = require("../common");
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 = import_util15.default.format(...args) + "\n";
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 = import_common10.configLoader.resolveConfigLocation(configFile);
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 import_common10.configLoader.loadConfig(configLocation, configCLIOverrides).catch((e) => null);
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 = import_common10.configLoader.resolveConfigLocation(configFile);
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 import_util16 = require("../util");
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, import_util16.relativeFilePath)(absolutePath)}`);
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()) {