playwright 1.55.0-alpha-2025-08-14 → 1.55.0-alpha-2025-08-15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of playwright might be problematic. Click here for more details.

package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 🎭 Playwright
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-140.0.7339.5-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-141.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-26.0-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-informational)](https://aka.ms/playwright/discord)
3
+ [![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-140.0.7339.16-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-141.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-26.0-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-informational)](https://aka.ms/playwright/discord)
4
4
 
5
5
  ## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
6
6
 
@@ -8,7 +8,7 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr
8
8
 
9
9
  | | Linux | macOS | Windows |
10
10
  | :--- | :---: | :---: | :---: |
11
- | Chromium <!-- GEN:chromium-version -->140.0.7339.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
11
+ | Chromium <!-- GEN:chromium-version -->140.0.7339.16<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
12
12
  | WebKit <!-- GEN:webkit-version -->26.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
13
13
  | Firefox <!-- GEN:firefox-version -->141.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
14
14
 
package/lib/program.js CHANGED
@@ -28,8 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var program_exports = {};
30
30
  __export(program_exports, {
31
- program: () => import_program2.program,
32
- withRunnerAndMutedWrite: () => withRunnerAndMutedWrite
31
+ program: () => import_program2.program
33
32
  });
34
33
  module.exports = __toCommonJS(program_exports);
35
34
  var import_fs = __toESM(require("fs"));
@@ -43,10 +42,10 @@ var import_base = require("./reporters/base");
43
42
  var import_html = require("./reporters/html");
44
43
  var import_merge = require("./reporters/merge");
45
44
  var import_projectUtils = require("./runner/projectUtils");
46
- var import_runner = require("./runner/runner");
47
45
  var testServer = __toESM(require("./runner/testServer"));
48
46
  var import_watchMode = require("./runner/watchMode");
49
- var import_util = require("./util");
47
+ var import_testRunner = require("./runner/testRunner");
48
+ var import_reporters = require("./runner/reporters");
50
49
  function addTestCommand(program3) {
51
50
  const command = program3.command("test [test-filter...]");
52
51
  command.description("run tests with Playwright Test");
@@ -78,44 +77,24 @@ Examples:
78
77
  $ npx playwright test --headed
79
78
  $ npx playwright test --project=webkit`);
80
79
  }
81
- function addListFilesCommand(program3) {
82
- const command = program3.command("list-files [file-filter...]", { hidden: true });
83
- command.description("List files with Playwright Test tests");
84
- command.option("-c, --config <file>", `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
85
- command.option("--project <project-name...>", `Only run tests from the specified list of projects, supports '*' wildcard (default: list all projects)`);
86
- command.action(async (args, opts) => listTestFiles(opts));
87
- }
88
80
  function addClearCacheCommand(program3) {
89
81
  const command = program3.command("clear-cache");
90
82
  command.description("clears build and test caches");
91
83
  command.option("-c, --config <file>", `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
92
84
  command.action(async (opts) => {
93
- const config = await (0, import_configLoader.loadConfigFromFile)(opts.config);
94
- const runner = new import_runner.Runner(config);
95
- const { status } = await runner.clearCache();
85
+ const runner = new import_testRunner.TestRunner((0, import_configLoader.resolveConfigLocation)(opts.config), {});
86
+ const { status } = await runner.clearCache((0, import_reporters.createErrorCollectingReporter)(import_base.terminalScreen));
96
87
  const exitCode = status === "interrupted" ? 130 : status === "passed" ? 0 : 1;
97
88
  (0, import_utils.gracefullyProcessExitDoNotHang)(exitCode);
98
89
  });
99
90
  }
100
- function addFindRelatedTestFilesCommand(program3) {
101
- const command = program3.command("find-related-test-files [source-files...]", { hidden: true });
102
- command.description("Returns the list of related tests to the given files");
103
- command.option("-c, --config <file>", `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
104
- command.action(async (files, options) => {
105
- const resolvedFiles = files.map((file) => import_path.default.resolve(process.cwd(), file));
106
- await withRunnerAndMutedWrite(options.config, (runner) => runner.findRelatedTestFiles(resolvedFiles));
107
- });
108
- }
109
91
  function addDevServerCommand(program3) {
110
92
  const command = program3.command("dev-server", { hidden: true });
111
93
  command.description("start dev server");
112
94
  command.option("-c, --config <file>", `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
113
95
  command.action(async (options) => {
114
- const config = await (0, import_configLoader.loadConfigFromFile)(options.config);
115
- const runner = new import_runner.Runner(config);
116
- const { status } = await runner.runDevServer();
117
- const exitCode = status === "interrupted" ? 130 : status === "passed" ? 0 : 1;
118
- (0, import_utils.gracefullyProcessExitDoNotHang)(exitCode);
96
+ const runner = new import_testRunner.TestRunner((0, import_configLoader.resolveConfigLocation)(options.config), {});
97
+ await runner.startDevServer((0, import_reporters.createErrorCollectingReporter)(import_base.terminalScreen), "in-process");
119
98
  });
120
99
  }
121
100
  function addTestServerCommand(program3) {
@@ -172,7 +151,6 @@ async function runTests(args, opts) {
172
151
  config.cliProjectFilter = opts.project || void 0;
173
152
  config.cliPassWithNoTests = !!opts.passWithNoTests;
174
153
  config.cliLastFailed = !!opts.lastFailed;
175
- config.cliFilterFile = opts.filter ? import_path.default.resolve(process.cwd(), opts.filter) : void 0;
176
154
  (0, import_projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
177
155
  if (opts.ui || opts.uiHost || opts.uiPort) {
178
156
  if (opts.onlyChanged)
@@ -207,8 +185,7 @@ async function runTests(args, opts) {
207
185
  (0, import_utils.gracefullyProcessExitDoNotHang)(exitCode2);
208
186
  return;
209
187
  }
210
- const runner = new import_runner.Runner(config);
211
- const status = await runner.runAllTests();
188
+ const status = await (0, import_testRunner.runAllTestsWithConfig)(config);
212
189
  await (0, import_utils.stopProfiling)("runner");
213
190
  const exitCode = status === "interrupted" ? 130 : status === "passed" ? 0 : 1;
214
191
  (0, import_utils.gracefullyProcessExitDoNotHang)(exitCode);
@@ -220,29 +197,6 @@ async function runTestServer(opts) {
220
197
  const exitCode = status === "interrupted" ? 130 : status === "passed" ? 0 : 1;
221
198
  (0, import_utils.gracefullyProcessExitDoNotHang)(exitCode);
222
199
  }
223
- async function withRunnerAndMutedWrite(configFile, callback) {
224
- const stdoutWrite = process.stdout.write.bind(process.stdout);
225
- process.stdout.write = (a, b, c) => process.stderr.write(a, b, c);
226
- try {
227
- const config = await (0, import_configLoader.loadConfigFromFile)(configFile);
228
- const runner = new import_runner.Runner(config);
229
- const result = await callback(runner);
230
- stdoutWrite(JSON.stringify(result, void 0, 2), () => {
231
- (0, import_utils.gracefullyProcessExitDoNotHang)(0);
232
- });
233
- } catch (e) {
234
- const error = (0, import_util.serializeError)(e);
235
- error.location = (0, import_base.prepareErrorStack)(e.stack).location;
236
- stdoutWrite(JSON.stringify({ error }, void 0, 2), () => {
237
- (0, import_utils.gracefullyProcessExitDoNotHang)(0);
238
- });
239
- }
240
- }
241
- async function listTestFiles(opts) {
242
- await withRunnerAndMutedWrite(opts.config, async (runner) => {
243
- return await runner.listTestFiles();
244
- });
245
- }
246
200
  async function mergeReports(reportDir, opts) {
247
201
  const configFile = opts.config;
248
202
  const config = configFile ? await (0, import_configLoader.loadConfigFromFile)(configFile) : await (0, import_configLoader.loadEmptyConfigForMergeReports)();
@@ -347,7 +301,6 @@ const testOptions = [
347
301
  ["-c, --config <file>", { description: `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"` }],
348
302
  ["--debug", { description: `Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --max-failures=1 --headed --workers=1" options` }],
349
303
  ["--fail-on-flaky-tests", { description: `Fail if any test is flagged as flaky (default: false)` }],
350
- ["--filter <file>", { description: `Path to a test filter file. See documentation for details.` }],
351
304
  ["--forbid-only", { description: `Fail if test.only is called (default: false)` }],
352
305
  ["--fully-parallel", { description: `Run all tests in parallel (default: false)` }],
353
306
  ["--global-timeout <timeout>", { description: `Maximum time this test suite can run in milliseconds (default: unlimited)` }],
@@ -381,14 +334,11 @@ const testOptions = [
381
334
  ];
382
335
  addTestCommand(import_program.program);
383
336
  addShowReportCommand(import_program.program);
384
- addListFilesCommand(import_program.program);
385
337
  addMergeReportsCommand(import_program.program);
386
338
  addClearCacheCommand(import_program.program);
387
- addFindRelatedTestFilesCommand(import_program.program);
388
339
  addDevServerCommand(import_program.program);
389
340
  addTestServerCommand(import_program.program);
390
341
  // Annotate the CommonJS export names for ESM import in node:
391
342
  0 && (module.exports = {
392
- program,
393
- withRunnerAndMutedWrite
343
+ program
394
344
  });
@@ -54,18 +54,20 @@ var import_utilsBundle2 = require("../utilsBundle");
54
54
  const kOutputSymbol = Symbol("output");
55
55
  const DEFAULT_TTY_WIDTH = 100;
56
56
  const DEFAULT_TTY_HEIGHT = 40;
57
+ const originalProcessStdout = process.stdout;
58
+ const originalProcessStderr = process.stderr;
57
59
  const terminalScreen = (() => {
58
- let isTTY = !!process.stdout.isTTY;
59
- let ttyWidth = process.stdout.columns || 0;
60
- let ttyHeight = process.stdout.rows || 0;
60
+ let isTTY = !!originalProcessStdout.isTTY;
61
+ let ttyWidth = originalProcessStdout.columns || 0;
62
+ let ttyHeight = originalProcessStdout.rows || 0;
61
63
  if (process.env.PLAYWRIGHT_FORCE_TTY === "false" || process.env.PLAYWRIGHT_FORCE_TTY === "0") {
62
64
  isTTY = false;
63
65
  ttyWidth = 0;
64
66
  ttyHeight = 0;
65
67
  } else if (process.env.PLAYWRIGHT_FORCE_TTY === "true" || process.env.PLAYWRIGHT_FORCE_TTY === "1") {
66
68
  isTTY = true;
67
- ttyWidth = process.stdout.columns || DEFAULT_TTY_WIDTH;
68
- ttyHeight = process.stdout.rows || DEFAULT_TTY_HEIGHT;
69
+ ttyWidth = originalProcessStdout.columns || DEFAULT_TTY_WIDTH;
70
+ ttyHeight = originalProcessStdout.rows || DEFAULT_TTY_HEIGHT;
69
71
  } else if (process.env.PLAYWRIGHT_FORCE_TTY) {
70
72
  isTTY = true;
71
73
  const sizeMatch = process.env.PLAYWRIGHT_FORCE_TTY.match(/^(\d+)x(\d+)$/);
@@ -92,7 +94,9 @@ const terminalScreen = (() => {
92
94
  isTTY,
93
95
  ttyWidth,
94
96
  ttyHeight,
95
- colors
97
+ colors,
98
+ stdout: originalProcessStdout,
99
+ stderr: originalProcessStderr
96
100
  };
97
101
  })();
98
102
  const nonTerminalScreen = {
@@ -260,22 +264,22 @@ class TerminalReporter {
260
264
  this._printSummary(summaryMessage);
261
265
  }
262
266
  _printFailures(failures) {
263
- console.log("");
267
+ this.writeLine("");
264
268
  failures.forEach((test, index) => {
265
- console.log(this.formatFailure(test, index + 1));
269
+ this.writeLine(this.formatFailure(test, index + 1));
266
270
  });
267
271
  }
268
272
  _printSlowTests() {
269
273
  const slowTests = this.getSlowTests();
270
274
  slowTests.forEach(([file, duration]) => {
271
- console.log(this.screen.colors.yellow(" Slow test file: ") + file + this.screen.colors.yellow(` (${(0, import_utilsBundle.ms)(duration)})`));
275
+ this.writeLine(this.screen.colors.yellow(" Slow test file: ") + file + this.screen.colors.yellow(` (${(0, import_utilsBundle.ms)(duration)})`));
272
276
  });
273
277
  if (slowTests.length)
274
- console.log(this.screen.colors.yellow(" Consider running tests from slow files in parallel. See: https://playwright.dev/docs/test-parallel"));
278
+ this.writeLine(this.screen.colors.yellow(" Consider running tests from slow files in parallel. See: https://playwright.dev/docs/test-parallel"));
275
279
  }
276
280
  _printSummary(summary) {
277
281
  if (summary.trim())
278
- console.log(summary);
282
+ this.writeLine(summary);
279
283
  }
280
284
  willRetry(test) {
281
285
  return test.outcome() === "unexpected" && test.results.length <= test.retries;
@@ -292,6 +296,9 @@ class TerminalReporter {
292
296
  formatError(error) {
293
297
  return formatError(this.screen, error);
294
298
  }
299
+ writeLine(line) {
300
+ this.screen.stdout?.write(line ? line + "\n" : "\n");
301
+ }
295
302
  }
296
303
  function formatFailure(screen, config, test, index) {
297
304
  const lines = [];
@@ -29,53 +29,53 @@ class DotReporter extends import_base.TerminalReporter {
29
29
  }
30
30
  onBegin(suite) {
31
31
  super.onBegin(suite);
32
- console.log(this.generateStartingMessage());
32
+ this.writeLine(this.generateStartingMessage());
33
33
  }
34
34
  onStdOut(chunk, test, result) {
35
35
  super.onStdOut(chunk, test, result);
36
36
  if (!this.config.quiet)
37
- process.stdout.write(chunk);
37
+ this.screen.stdout.write(chunk);
38
38
  }
39
39
  onStdErr(chunk, test, result) {
40
40
  super.onStdErr(chunk, test, result);
41
41
  if (!this.config.quiet)
42
- process.stderr.write(chunk);
42
+ this.screen.stderr.write(chunk);
43
43
  }
44
44
  onTestEnd(test, result) {
45
45
  super.onTestEnd(test, result);
46
46
  if (this._counter === 80) {
47
- process.stdout.write("\n");
47
+ this.screen.stdout.write("\n");
48
48
  this._counter = 0;
49
49
  }
50
50
  ++this._counter;
51
51
  if (result.status === "skipped") {
52
- process.stdout.write(this.screen.colors.yellow("\xB0"));
52
+ this.screen.stdout.write(this.screen.colors.yellow("\xB0"));
53
53
  return;
54
54
  }
55
55
  if (this.willRetry(test)) {
56
- process.stdout.write(this.screen.colors.gray("\xD7"));
56
+ this.screen.stdout.write(this.screen.colors.gray("\xD7"));
57
57
  return;
58
58
  }
59
59
  switch (test.outcome()) {
60
60
  case "expected":
61
- process.stdout.write(this.screen.colors.green("\xB7"));
61
+ this.screen.stdout.write(this.screen.colors.green("\xB7"));
62
62
  break;
63
63
  case "unexpected":
64
- process.stdout.write(this.screen.colors.red(result.status === "timedOut" ? "T" : "F"));
64
+ this.screen.stdout.write(this.screen.colors.red(result.status === "timedOut" ? "T" : "F"));
65
65
  break;
66
66
  case "flaky":
67
- process.stdout.write(this.screen.colors.yellow("\xB1"));
67
+ this.screen.stdout.write(this.screen.colors.yellow("\xB1"));
68
68
  break;
69
69
  }
70
70
  }
71
71
  onError(error) {
72
72
  super.onError(error);
73
- console.log("\n" + this.formatError(error).message);
73
+ this.writeLine("\n" + this.formatError(error).message);
74
74
  this._counter = 0;
75
75
  }
76
76
  async onEnd(result) {
77
77
  await super.onEnd(result);
78
- process.stdout.write("\n");
78
+ this.screen.stdout.write("\n");
79
79
  this.epilogue(true);
80
80
  }
81
81
  }
@@ -41,7 +41,8 @@ class GitHubLogger {
41
41
  _log(message, type = "notice", options = {}) {
42
42
  message = message.replace(/\n/g, "%0A");
43
43
  const configs = Object.entries(options).map(([key, option]) => `${key}=${option}`).join(",");
44
- console.log((0, import_util.stripAnsiEscapes)(`::${type} ${configs}::${message}`));
44
+ process.stdout.write((0, import_util.stripAnsiEscapes)(`::${type} ${configs}::${message}
45
+ `));
45
46
  }
46
47
  debug(message, options) {
47
48
  this._log(message, "debug", options);
@@ -76,12 +76,12 @@ class HtmlReporter {
76
76
  if (reportedWarnings.has(key))
77
77
  continue;
78
78
  reportedWarnings.add(key);
79
- console.log(import_utils2.colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));
80
- console.log(`
79
+ writeLine(import_utils2.colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));
80
+ writeLine(`
81
81
  html reporter folder: ${import_utils2.colors.bold(outputFolder)}
82
82
  test results folder: ${import_utils2.colors.bold(project.outputDir)}`);
83
- console.log("");
84
- console.log(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.
83
+ writeLine("");
84
+ writeLine(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.
85
85
  `);
86
86
  }
87
87
  }
@@ -128,9 +128,9 @@ class HtmlReporter {
128
128
  const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? "" : " " + import_path.default.relative(process.cwd(), this._outputFolder);
129
129
  const hostArg = this._host ? ` --host ${this._host}` : "";
130
130
  const portArg = this._port ? ` --port ${this._port}` : "";
131
- console.log("");
132
- console.log("To open last HTML report run:");
133
- console.log(import_utils2.colors.cyan(`
131
+ writeLine("");
132
+ writeLine("To open last HTML report run:");
133
+ writeLine(import_utils2.colors.cyan(`
134
134
  ${packageManagerCommand} playwright show-report${relativeReportPath}${hostArg}${portArg}
135
135
  `));
136
136
  }
@@ -145,7 +145,7 @@ function getHtmlReportOptionProcessEnv() {
145
145
  if (!htmlOpenEnv)
146
146
  return void 0;
147
147
  if (!isHtmlReportOption(htmlOpenEnv)) {
148
- console.log(import_utils2.colors.red(`Configuration Error: HTML reporter Invalid value for PLAYWRIGHT_HTML_OPEN: ${htmlOpenEnv}. Valid values are: ${htmlReportOptions.join(", ")}`));
148
+ writeLine(import_utils2.colors.red(`Configuration Error: HTML reporter Invalid value for PLAYWRIGHT_HTML_OPEN: ${htmlOpenEnv}. Valid values are: ${htmlReportOptions.join(", ")}`));
149
149
  return void 0;
150
150
  }
151
151
  return htmlOpenEnv;
@@ -158,15 +158,15 @@ async function showHTMLReport(reportFolder, host = "localhost", port, testId) {
158
158
  try {
159
159
  (0, import_utils.assert)(import_fs.default.statSync(folder).isDirectory());
160
160
  } catch (e) {
161
- console.log(import_utils2.colors.red(`No report found at "${folder}"`));
161
+ writeLine(import_utils2.colors.red(`No report found at "${folder}"`));
162
162
  (0, import_utils.gracefullyProcessExitDoNotHang)(1);
163
163
  return;
164
164
  }
165
165
  const server = startHtmlReportServer(folder);
166
166
  await server.start({ port, host, preferredPort: port ? void 0 : 9323 });
167
167
  let url = server.urlPrefix("human-readable");
168
- console.log("");
169
- console.log(import_utils2.colors.cyan(` Serving HTML report at ${url}. Press Ctrl+C to quit.`));
168
+ writeLine("");
169
+ writeLine(import_utils2.colors.cyan(` Serving HTML report at ${url}. Press Ctrl+C to quit.`));
170
170
  if (testId)
171
171
  url += `#?testId=${testId}`;
172
172
  url = url.replace("0.0.0.0", "localhost");
@@ -620,6 +620,9 @@ function createErrorCodeframe(message, location) {
620
620
  }
621
621
  );
622
622
  }
623
+ function writeLine(line) {
624
+ process.stdout.write(line + "\n");
625
+ }
623
626
  var html_default = HtmlReporter;
624
627
  // Annotate the CommonJS export names for ESM import in node:
625
628
  0 && (module.exports = {
@@ -37,10 +37,11 @@ var import_base = require("./base");
37
37
  var import_multiplexer = require("./multiplexer");
38
38
  var import_test = require("../common/test");
39
39
  var import_babelBundle = require("../transform/babelBundle");
40
+ var import_reporterV2 = require("./reporterV2");
40
41
  class InternalReporter {
41
42
  constructor(reporters) {
42
43
  this._didBegin = false;
43
- this._reporter = new import_multiplexer.Multiplexer(reporters);
44
+ this._reporter = new import_multiplexer.Multiplexer(reporters.map(import_reporterV2.wrapReporterAsV2));
44
45
  }
45
46
  version() {
46
47
  return "v2";
@@ -33,18 +33,18 @@ class LineReporter extends import_base.TerminalReporter {
33
33
  super.onBegin(suite);
34
34
  const startingMessage = this.generateStartingMessage();
35
35
  if (startingMessage) {
36
- console.log(startingMessage);
37
- console.log();
36
+ this.writeLine(startingMessage);
37
+ this.writeLine();
38
38
  }
39
39
  this._didBegin = true;
40
40
  }
41
41
  onStdOut(chunk, test, result) {
42
42
  super.onStdOut(chunk, test, result);
43
- this._dumpToStdio(test, chunk, process.stdout);
43
+ this._dumpToStdio(test, chunk, this.screen.stdout);
44
44
  }
45
45
  onStdErr(chunk, test, result) {
46
46
  super.onStdErr(chunk, test, result);
47
- this._dumpToStdio(test, chunk, process.stderr);
47
+ this._dumpToStdio(test, chunk, this.screen.stderr);
48
48
  }
49
49
  _dumpToStdio(test, chunk, stream) {
50
50
  if (this.config.quiet)
@@ -59,8 +59,8 @@ class LineReporter extends import_base.TerminalReporter {
59
59
  }
60
60
  stream.write(chunk);
61
61
  if (chunk[chunk.length - 1] !== "\n")
62
- console.log();
63
- console.log();
62
+ this.writeLine();
63
+ this.writeLine();
64
64
  }
65
65
  onTestBegin(test, result) {
66
66
  ++this._current;
@@ -78,9 +78,9 @@ class LineReporter extends import_base.TerminalReporter {
78
78
  super.onTestEnd(test, result);
79
79
  if (!this.willRetry(test) && (test.outcome() === "flaky" || test.outcome() === "unexpected" || result.status === "interrupted")) {
80
80
  if (!process.env.PW_TEST_DEBUG_REPORTERS)
81
- process.stdout.write(`\x1B[1A\x1B[2K`);
82
- console.log(this.formatFailure(test, ++this._failures));
83
- console.log();
81
+ this.screen.stdout.write(`\x1B[1A\x1B[2K`);
82
+ this.writeLine(this.formatFailure(test, ++this._failures));
83
+ this.writeLine();
84
84
  }
85
85
  }
86
86
  _updateLine(test, result, step) {
@@ -89,23 +89,23 @@ class LineReporter extends import_base.TerminalReporter {
89
89
  const currentRetrySuffix = result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : "";
90
90
  const title = this.formatTestTitle(test, step) + currentRetrySuffix;
91
91
  if (process.env.PW_TEST_DEBUG_REPORTERS)
92
- process.stdout.write(`${prefix + title}
92
+ this.screen.stdout.write(`${prefix + title}
93
93
  `);
94
94
  else
95
- process.stdout.write(`\x1B[1A\x1B[2K${prefix + this.fitToScreen(title, prefix)}
95
+ this.screen.stdout.write(`\x1B[1A\x1B[2K${prefix + this.fitToScreen(title, prefix)}
96
96
  `);
97
97
  }
98
98
  onError(error) {
99
99
  super.onError(error);
100
100
  const message = this.formatError(error).message + "\n";
101
101
  if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)
102
- process.stdout.write(`\x1B[1A\x1B[2K`);
103
- process.stdout.write(message);
104
- console.log();
102
+ this.screen.stdout.write(`\x1B[1A\x1B[2K`);
103
+ this.screen.stdout.write(message);
104
+ this.writeLine();
105
105
  }
106
106
  async onEnd(result) {
107
107
  if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)
108
- process.stdout.write(`\x1B[1A\x1B[2K`);
108
+ this.screen.stdout.write(`\x1B[1A\x1B[2K`);
109
109
  await super.onEnd(result);
110
110
  this.epilogue(false);
111
111
  }
@@ -44,8 +44,8 @@ class ListReporter extends import_base.TerminalReporter {
44
44
  super.onBegin(suite);
45
45
  const startingMessage = this.generateStartingMessage();
46
46
  if (startingMessage) {
47
- console.log(startingMessage);
48
- console.log();
47
+ this.writeLine(startingMessage);
48
+ this.writeLine("");
49
49
  }
50
50
  }
51
51
  onTestBegin(test, result) {
@@ -61,11 +61,11 @@ class ListReporter extends import_base.TerminalReporter {
61
61
  }
62
62
  onStdOut(chunk, test, result) {
63
63
  super.onStdOut(chunk, test, result);
64
- this._dumpToStdio(test, chunk, process.stdout);
64
+ this._dumpToStdio(test, chunk, this.screen.stdout);
65
65
  }
66
66
  onStdErr(chunk, test, result) {
67
67
  super.onStdErr(chunk, test, result);
68
- this._dumpToStdio(test, chunk, process.stderr);
68
+ this._dumpToStdio(test, chunk, this.screen.stderr);
69
69
  }
70
70
  getStepIndex(testIndex, result, step) {
71
71
  if (this._stepIndex.has(step))
@@ -115,7 +115,7 @@ class ListReporter extends import_base.TerminalReporter {
115
115
  _maybeWriteNewLine() {
116
116
  if (this._needNewLine) {
117
117
  this._needNewLine = false;
118
- process.stdout.write("\n");
118
+ this.screen.stdout.write("\n");
119
119
  ++this._lastRow;
120
120
  this._lastColumn = 0;
121
121
  }
@@ -183,10 +183,10 @@ class ListReporter extends import_base.TerminalReporter {
183
183
  _appendLine(text, prefix) {
184
184
  const line = prefix + this.fitToScreen(text, prefix);
185
185
  if (process.env.PW_TEST_DEBUG_REPORTERS) {
186
- process.stdout.write("#" + this._lastRow + " : " + line + "\n");
186
+ this.screen.stdout.write("#" + this._lastRow + " : " + line + "\n");
187
187
  } else {
188
- process.stdout.write(line);
189
- process.stdout.write("\n");
188
+ this.screen.stdout.write(line);
189
+ this.screen.stdout.write("\n");
190
190
  }
191
191
  ++this._lastRow;
192
192
  this._lastColumn = 0;
@@ -194,17 +194,17 @@ class ListReporter extends import_base.TerminalReporter {
194
194
  _updateLine(row, text, prefix) {
195
195
  const line = prefix + this.fitToScreen(text, prefix);
196
196
  if (process.env.PW_TEST_DEBUG_REPORTERS)
197
- process.stdout.write("#" + row + " : " + line + "\n");
197
+ this.screen.stdout.write("#" + row + " : " + line + "\n");
198
198
  else
199
199
  this._updateLineForTTY(row, line);
200
200
  }
201
201
  _updateLineForTTY(row, line) {
202
202
  if (row !== this._lastRow)
203
- process.stdout.write(`\x1B[${this._lastRow - row}A`);
204
- process.stdout.write("\x1B[2K\x1B[0G");
205
- process.stdout.write(line);
203
+ this.screen.stdout.write(`\x1B[${this._lastRow - row}A`);
204
+ this.screen.stdout.write("\x1B[2K\x1B[0G");
205
+ this.screen.stdout.write(line);
206
206
  if (row !== this._lastRow)
207
- process.stdout.write(`\x1B[${this._lastRow - row}E`);
207
+ this.screen.stdout.write(`\x1B[${this._lastRow - row}E`);
208
208
  }
209
209
  _testPrefix(index, statusMark) {
210
210
  const statusMarkLength = (0, import_util.stripAnsiEscapes)(statusMark).length;
@@ -219,11 +219,11 @@ class ListReporter extends import_base.TerminalReporter {
219
219
  this._maybeWriteNewLine();
220
220
  const message = this.formatError(error).message + "\n";
221
221
  this._updateLineCountAndNewLineFlagForOutput(message);
222
- process.stdout.write(message);
222
+ this.screen.stdout.write(message);
223
223
  }
224
224
  async onEnd(result) {
225
225
  await super.onEnd(result);
226
- process.stdout.write("\n");
226
+ this.screen.stdout.write("\n");
227
227
  this.epilogue(true);
228
228
  }
229
229
  }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var listModeReporter_exports = {};
30
+ __export(listModeReporter_exports, {
31
+ default: () => listModeReporter_default
32
+ });
33
+ module.exports = __toCommonJS(listModeReporter_exports);
34
+ var import_path = __toESM(require("path"));
35
+ var import_base = require("./base");
36
+ class ListModeReporter {
37
+ constructor(options) {
38
+ this.screen = options?.screen ?? import_base.terminalScreen;
39
+ }
40
+ version() {
41
+ return "v2";
42
+ }
43
+ onConfigure(config) {
44
+ this.config = config;
45
+ }
46
+ onBegin(suite) {
47
+ this._writeLine(`Listing tests:`);
48
+ const tests = suite.allTests();
49
+ const files = /* @__PURE__ */ new Set();
50
+ for (const test of tests) {
51
+ const [, projectName, , ...titles] = test.titlePath();
52
+ const location = `${import_path.default.relative(this.config.rootDir, test.location.file)}:${test.location.line}:${test.location.column}`;
53
+ const projectTitle = projectName ? `[${projectName}] \u203A ` : "";
54
+ this._writeLine(` ${projectTitle}${location} \u203A ${titles.join(" \u203A ")}`);
55
+ files.add(test.location.file);
56
+ }
57
+ this._writeLine(`Total: ${tests.length} ${tests.length === 1 ? "test" : "tests"} in ${files.size} ${files.size === 1 ? "file" : "files"}`);
58
+ }
59
+ onError(error) {
60
+ this.screen.stderr.write("\n" + (0, import_base.formatError)(import_base.terminalScreen, error).message + "\n");
61
+ }
62
+ _writeLine(line) {
63
+ this.screen.stdout.write(line + "\n");
64
+ }
65
+ }
66
+ var listModeReporter_default = ListModeReporter;
@@ -33,7 +33,6 @@ __export(reporters_exports, {
33
33
  createReporters: () => createReporters
34
34
  });
35
35
  module.exports = __toCommonJS(reporters_exports);
36
- var import_path = __toESM(require("path"));
37
36
  var import_utils = require("playwright-core/lib/utils");
38
37
  var import_loadUtils = require("./loadUtils");
39
38
  var import_base = require("../reporters/base");
@@ -46,13 +45,14 @@ var import_json = __toESM(require("../reporters/json"));
46
45
  var import_junit = __toESM(require("../reporters/junit"));
47
46
  var import_line = __toESM(require("../reporters/line"));
48
47
  var import_list = __toESM(require("../reporters/list"));
48
+ var import_listModeReporter = __toESM(require("../reporters/listModeReporter"));
49
49
  var import_reporterV2 = require("../reporters/reporterV2");
50
50
  async function createReporters(config, mode, isTestServer, descriptions) {
51
51
  const defaultReporters = {
52
52
  blob: import_blob.BlobReporter,
53
- dot: mode === "list" ? ListModeReporter : import_dot.default,
54
- line: mode === "list" ? ListModeReporter : import_line.default,
55
- list: mode === "list" ? ListModeReporter : import_list.default,
53
+ dot: mode === "list" ? import_listModeReporter.default : import_dot.default,
54
+ line: mode === "list" ? import_listModeReporter.default : import_line.default,
55
+ list: mode === "list" ? import_listModeReporter.default : import_list.default,
56
56
  github: import_github.default,
57
57
  json: import_json.default,
58
58
  junit: import_junit.default,
@@ -81,7 +81,7 @@ async function createReporters(config, mode, isTestServer, descriptions) {
81
81
  const someReporterPrintsToStdio = reporters.some((r) => r.printsToStdio ? r.printsToStdio() : true);
82
82
  if (reporters.length && !someReporterPrintsToStdio) {
83
83
  if (mode === "list")
84
- reporters.unshift(new ListModeReporter());
84
+ reporters.unshift(new import_listModeReporter.default());
85
85
  else if (mode !== "merge")
86
86
  reporters.unshift(!process.env.CI ? new import_line.default() : new import_dot.default());
87
87
  }
@@ -93,14 +93,13 @@ async function createReporterForTestServer(file, messageSink) {
93
93
  _send: messageSink
94
94
  }));
95
95
  }
96
- function createErrorCollectingReporter(screen, writeToConsole) {
96
+ function createErrorCollectingReporter(screen) {
97
97
  const errors = [];
98
98
  return {
99
99
  version: () => "v2",
100
100
  onError(error) {
101
101
  errors.push(error);
102
- if (writeToConsole)
103
- process.stdout.write((0, import_base.formatError)(screen, error).message + "\n");
102
+ screen.stderr?.write((0, import_base.formatError)(screen, error).message + "\n");
104
103
  },
105
104
  errors: () => errors
106
105
  };
@@ -130,30 +129,6 @@ function computeCommandHash(config) {
130
129
  parts.push((0, import_utils.calculateSha1)(JSON.stringify(command)).substring(0, 7));
131
130
  return parts.join("-");
132
131
  }
133
- class ListModeReporter {
134
- version() {
135
- return "v2";
136
- }
137
- onConfigure(config) {
138
- this.config = config;
139
- }
140
- onBegin(suite) {
141
- console.log(`Listing tests:`);
142
- const tests = suite.allTests();
143
- const files = /* @__PURE__ */ new Set();
144
- for (const test of tests) {
145
- const [, projectName, , ...titles] = test.titlePath();
146
- const location = `${import_path.default.relative(this.config.rootDir, test.location.file)}:${test.location.line}:${test.location.column}`;
147
- const projectTitle = projectName ? `[${projectName}] \u203A ` : "";
148
- console.log(` ${projectTitle}${location} \u203A ${titles.join(" \u203A ")}`);
149
- files.add(test.location.file);
150
- }
151
- console.log(`Total: ${tests.length} ${tests.length === 1 ? "test" : "tests"} in ${files.size} ${files.size === 1 ? "file" : "files"}`);
152
- }
153
- onError(error) {
154
- console.error("\n" + (0, import_base.formatError)(import_base.terminalScreen, error).message);
155
- }
156
- }
157
132
  // Annotate the CommonJS export names for ESM import in node:
158
133
  0 && (module.exports = {
159
134
  createErrorCollectingReporter,
@@ -247,15 +247,6 @@ function createLoadTask(mode, options) {
247
247
  const changedFiles = await (0, import_vcs.detectChangedTestFiles)(testRun.config.cliOnlyChanged, testRun.config.configDir);
248
248
  testRun.config.preOnlyTestFilters.push((test) => changedFiles.has(test.location.file));
249
249
  }
250
- if (testRun.config.cliFilterFile) {
251
- try {
252
- testRun.config.preOnlyTestFilters.push(await (0, import_util2.loadTestFilterFile)(testRun.config.cliFilterFile));
253
- } catch (error) {
254
- if (options.failOnLoadErrors)
255
- throw error;
256
- softErrors.push(error);
257
- }
258
- }
259
250
  testRun.rootSuite = await (0, import_loadUtils.createRootSuite)(testRun, options.failOnLoadErrors ? errors : softErrors, !!options.filterOnly);
260
251
  testRun.failureTracker.onRootSuite(testRun.rootSuite);
261
252
  if (options.failOnLoadErrors && !testRun.rootSuite.allTests().length && !testRun.config.cliPassWithNoTests && !testRun.config.config.shard && !testRun.config.cliOnlyChanged) {
@@ -29,7 +29,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var testRunner_exports = {};
30
30
  __export(testRunner_exports, {
31
31
  TestRunner: () => TestRunner,
32
- TestRunnerEvent: () => TestRunnerEvent
32
+ TestRunnerEvent: () => TestRunnerEvent,
33
+ runAllTestsWithConfig: () => runAllTestsWithConfig
33
34
  });
34
35
  module.exports = __toCommonJS(testRunner_exports);
35
36
  var import_events = __toESM(require("events"));
@@ -48,6 +49,7 @@ var import_compilationCache = require("../transform/compilationCache");
48
49
  var import_util = require("../util");
49
50
  var import_reporters = require("./reporters");
50
51
  var import_tasks = require("./tasks");
52
+ var import_lastRun = require("./lastRun");
51
53
  const TestRunnerEvent = {
52
54
  TestFilesChanged: "testFilesChanged",
53
55
  RecoverFromStepError: "recoverFromStepError"
@@ -117,14 +119,15 @@ class TestRunner extends import_events.default {
117
119
  this._globalSetup = void 0;
118
120
  return { status };
119
121
  }
120
- async startDevServer(userReporters) {
122
+ async startDevServer(userReporter, mode) {
121
123
  await this.stopDevServer();
122
- const reporter = new import_internalReporter.InternalReporter(userReporters);
124
+ const reporter = new import_internalReporter.InternalReporter([userReporter]);
123
125
  const config = await this._loadConfigOrReportError(reporter);
124
126
  if (!config)
125
127
  return { status: "failed" };
126
128
  const { status, cleanup } = await (0, import_tasks.runTasksDeferCleanup)(new import_tasks.TestRun(config, reporter), [
127
- (0, import_tasks.createLoadTask)("out-of-process", { failOnLoadErrors: true, filterOnly: false }),
129
+ ...(0, import_tasks.createPluginSetupTasks)(config),
130
+ (0, import_tasks.createLoadTask)(mode, { failOnLoadErrors: true, filterOnly: false }),
128
131
  (0, import_tasks.createStartDevServerTask)()
129
132
  ]);
130
133
  if (status !== "passed")
@@ -139,31 +142,33 @@ class TestRunner extends import_events.default {
139
142
  this._devServer = void 0;
140
143
  return { status };
141
144
  }
142
- async clearCache() {
143
- const reporter = new import_internalReporter.InternalReporter([]);
145
+ async clearCache(userReporter) {
146
+ const reporter = new import_internalReporter.InternalReporter(userReporter ? [userReporter] : []);
144
147
  const config = await this._loadConfigOrReportError(reporter);
145
148
  if (!config)
146
- return;
147
- await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
149
+ return { status: "failed" };
150
+ const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
151
+ ...(0, import_tasks.createPluginSetupTasks)(config),
148
152
  (0, import_tasks.createClearCacheTask)(config)
149
153
  ]);
154
+ return { status };
150
155
  }
151
- async listFiles(userReporters, params) {
152
- const reporter = new import_internalReporter.InternalReporter(userReporters);
156
+ async listFiles(userReporter, projects) {
157
+ const reporter = new import_internalReporter.InternalReporter([userReporter]);
153
158
  const config = await this._loadConfigOrReportError(reporter);
154
159
  if (!config)
155
160
  return { status: "failed" };
156
- config.cliProjectFilter = params.projects?.length ? params.projects : void 0;
161
+ config.cliProjectFilter = projects?.length ? projects : void 0;
157
162
  const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
158
163
  (0, import_tasks.createListFilesTask)(),
159
164
  (0, import_tasks.createReportBeginTask)()
160
165
  ]);
161
166
  return { status };
162
167
  }
163
- async listTests(userReporters, params) {
168
+ async listTests(userReporter, params) {
164
169
  let result;
165
170
  this._queue = this._queue.then(async () => {
166
- const { config, status } = await this._innerListTests(userReporters, params);
171
+ const { config, status } = await this._innerListTests(userReporter, params);
167
172
  if (config)
168
173
  await this._updateWatchedDirs(config);
169
174
  result = { status };
@@ -171,13 +176,13 @@ class TestRunner extends import_events.default {
171
176
  await this._queue;
172
177
  return result;
173
178
  }
174
- async _innerListTests(userReporters, params) {
179
+ async _innerListTests(userReporter, params) {
175
180
  const overrides = {
176
181
  ...this._configCLIOverrides,
177
182
  repeatEach: 1,
178
183
  retries: 0
179
184
  };
180
- const reporter = new import_internalReporter.InternalReporter(userReporters);
185
+ const reporter = new import_internalReporter.InternalReporter([userReporter]);
181
186
  const config = await this._loadConfigOrReportError(reporter, overrides);
182
187
  if (!config)
183
188
  return { status: "failed" };
@@ -210,10 +215,10 @@ class TestRunner extends import_events.default {
210
215
  async _updateWatcher(reportPending) {
211
216
  await this._watcher.update([...this._watchedProjectDirs, ...this._watchedTestDependencies], [...this._ignoredProjectOutputs], reportPending);
212
217
  }
213
- async runTests(userReporters, params) {
218
+ async runTests(userReporter, params) {
214
219
  let result = { status: "passed" };
215
220
  this._queue = this._queue.then(async () => {
216
- result = await this._innerRunTests(userReporters, params).catch((e) => {
221
+ result = await this._innerRunTests(userReporter, params).catch((e) => {
217
222
  printInternalError(e);
218
223
  return { status: "failed" };
219
224
  });
@@ -221,7 +226,7 @@ class TestRunner extends import_events.default {
221
226
  await this._queue;
222
227
  return result;
223
228
  }
224
- async _innerRunTests(userReporters, params) {
229
+ async _innerRunTests(userReporter, params) {
225
230
  await this.stopTests();
226
231
  const overrides = {
227
232
  ...this._configCLIOverrides,
@@ -246,7 +251,7 @@ class TestRunner extends import_events.default {
246
251
  process.env.PW_LIVE_TRACE_STACKS = "1";
247
252
  else
248
253
  process.env.PW_LIVE_TRACE_STACKS = void 0;
249
- const config = await this._loadConfigOrReportError(new import_internalReporter.InternalReporter(userReporters), overrides);
254
+ const config = await this._loadConfigOrReportError(new import_internalReporter.InternalReporter([userReporter]), overrides);
250
255
  if (!config)
251
256
  return { status: "failed" };
252
257
  config.cliListOnly = false;
@@ -261,7 +266,7 @@ class TestRunner extends import_events.default {
261
266
  config.preOnlyTestFilters.push((test) => testIdSet.has(test.id));
262
267
  }
263
268
  const configReporters = await (0, import_reporters.createReporters)(config, "test", true);
264
- const reporter = new import_internalReporter.InternalReporter([...configReporters, ...userReporters]);
269
+ const reporter = new import_internalReporter.InternalReporter([...configReporters, userReporter]);
265
270
  const stop = new import_utils.ManualPromise();
266
271
  const tasks = [
267
272
  (0, import_tasks.createApplyRebaselinesTask)(),
@@ -295,26 +300,27 @@ class TestRunner extends import_events.default {
295
300
  if (recoveryPromise)
296
301
  recoveryPromise.resolve(params);
297
302
  }
298
- async watch(params) {
303
+ async watch(fileNames) {
299
304
  this._watchedTestDependencies = /* @__PURE__ */ new Set();
300
- for (const fileName of params.fileNames) {
305
+ for (const fileName of fileNames) {
301
306
  this._watchedTestDependencies.add(fileName);
302
307
  (0, import_compilationCache.dependenciesForTestFile)(fileName).forEach((file) => this._watchedTestDependencies.add(file));
303
308
  }
304
309
  await this._updateWatcher(true);
305
310
  }
306
- async findRelatedTestFiles(params) {
311
+ async findRelatedTestFiles(files, userReporter) {
307
312
  const errorReporter = (0, import_reporters.createErrorCollectingReporter)(import_base.internalScreen);
308
- const reporter = new import_internalReporter.InternalReporter([errorReporter]);
313
+ const reporter = new import_internalReporter.InternalReporter(userReporter ? [userReporter, errorReporter] : [errorReporter]);
309
314
  const config = await this._loadConfigOrReportError(reporter);
310
315
  if (!config)
311
316
  return { errors: errorReporter.errors(), testFiles: [] };
312
317
  const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
318
+ ...(0, import_tasks.createPluginSetupTasks)(config),
313
319
  (0, import_tasks.createLoadTask)("out-of-process", { failOnLoadErrors: true, filterOnly: false, populateDependencies: true })
314
320
  ]);
315
321
  if (status !== "passed")
316
322
  return { errors: errorReporter.errors(), testFiles: [] };
317
- return { testFiles: (0, import_compilationCache.affectedTestFiles)(params.files) };
323
+ return { testFiles: (0, import_compilationCache.affectedTestFiles)(files) };
318
324
  }
319
325
  async stopTests() {
320
326
  this._testRun?.stop?.resolve();
@@ -365,8 +371,32 @@ async function resolveCtDirs(config) {
365
371
  templateDir
366
372
  };
367
373
  }
374
+ async function runAllTestsWithConfig(config) {
375
+ const listOnly = config.cliListOnly;
376
+ (0, import_gitCommitInfoPlugin.addGitCommitInfoPlugin)(config);
377
+ (0, import_webServerPlugin.webServerPluginsForConfig)(config).forEach((p) => config.plugins.push({ factory: p }));
378
+ const reporters = await (0, import_reporters.createReporters)(config, listOnly ? "list" : "test", false);
379
+ const lastRun = new import_lastRun.LastRunReporter(config);
380
+ if (config.cliLastFailed)
381
+ await lastRun.filterLastFailed();
382
+ const reporter = new import_internalReporter.InternalReporter([...reporters, lastRun]);
383
+ const tasks = listOnly ? [
384
+ (0, import_tasks.createLoadTask)("in-process", { failOnLoadErrors: true, filterOnly: false }),
385
+ (0, import_tasks.createReportBeginTask)()
386
+ ] : [
387
+ (0, import_tasks.createApplyRebaselinesTask)(),
388
+ ...(0, import_tasks.createGlobalSetupTasks)(config),
389
+ (0, import_tasks.createLoadTask)("in-process", { filterOnly: true, failOnLoadErrors: true }),
390
+ ...(0, import_tasks.createRunTestsTasks)(config)
391
+ ];
392
+ const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), tasks, config.config.globalTimeout);
393
+ await new Promise((resolve) => process.stdout.write("", () => resolve()));
394
+ await new Promise((resolve) => process.stderr.write("", () => resolve()));
395
+ return status;
396
+ }
368
397
  // Annotate the CommonJS export names for ESM import in node:
369
398
  0 && (module.exports = {
370
399
  TestRunner,
371
- TestRunnerEvent
400
+ TestRunnerEvent,
401
+ runAllTestsWithConfig
372
402
  });
@@ -134,7 +134,7 @@ class TestServerDispatcher {
134
134
  async startDevServer(params) {
135
135
  await this.stopDevServer({});
136
136
  const { reporter, report } = await this._collectingReporter();
137
- const { status } = await this._testRunner.startDevServer([reporter]);
137
+ const { status } = await this._testRunner.startDevServer(reporter, "out-of-process");
138
138
  return { report, status };
139
139
  }
140
140
  async stopDevServer(params) {
@@ -148,27 +148,27 @@ class TestServerDispatcher {
148
148
  }
149
149
  async listFiles(params) {
150
150
  const { reporter, report } = await this._collectingReporter();
151
- const { status } = await this._testRunner.listFiles([reporter], params);
151
+ const { status } = await this._testRunner.listFiles(reporter, params.projects);
152
152
  return { report, status };
153
153
  }
154
154
  async listTests(params) {
155
155
  const { reporter, report } = await this._collectingReporter();
156
- const { status } = await this._testRunner.listTests([reporter], params);
156
+ const { status } = await this._testRunner.listTests(reporter, params);
157
157
  return { report, status };
158
158
  }
159
159
  async runTests(params) {
160
160
  const wireReporter = await this._wireReporter((e) => this._dispatchEvent("report", e));
161
- const { status } = await this._testRunner.runTests([wireReporter], params);
161
+ const { status } = await this._testRunner.runTests(wireReporter, params);
162
162
  return { status };
163
163
  }
164
164
  async resumeAfterStepError(params) {
165
165
  await this._testRunner.resumeAfterStepError(params);
166
166
  }
167
167
  async watch(params) {
168
- await this._testRunner.watch(params);
168
+ await this._testRunner.watch(params.fileNames);
169
169
  }
170
170
  async findRelatedTestFiles(params) {
171
- return this._testRunner.findRelatedTestFiles(params);
171
+ return this._testRunner.findRelatedTestFiles(params.files);
172
172
  }
173
173
  async stopTests() {
174
174
  await this._testRunner.stopTests();
@@ -183,14 +183,16 @@ class TestServerDispatcher {
183
183
  return originalStderrWrite.apply(process.stderr, [string]);
184
184
  };
185
185
  }
186
- process.stdout.write = (chunk) => {
186
+ const stdoutWrite = (chunk) => {
187
187
  this._dispatchEvent("stdio", chunkToPayload("stdout", chunk));
188
188
  return true;
189
189
  };
190
- process.stderr.write = (chunk) => {
190
+ const stderrWrite = (chunk) => {
191
191
  this._dispatchEvent("stdio", chunkToPayload("stderr", chunk));
192
192
  return true;
193
193
  };
194
+ process.stdout.write = stdoutWrite;
195
+ process.stderr.write = stderrWrite;
194
196
  } else {
195
197
  import_utilsBundle.debug.log = originalDebugLog;
196
198
  process.stdout.write = originalStdoutWrite;
@@ -40,11 +40,11 @@ __export(transform_exports, {
40
40
  wrapFunctionWithLocation: () => wrapFunctionWithLocation
41
41
  });
42
42
  module.exports = __toCommonJS(transform_exports);
43
- var import_crypto = __toESM(require("crypto"));
44
43
  var import_fs = __toESM(require("fs"));
45
44
  var import_module = __toESM(require("module"));
46
45
  var import_path = __toESM(require("path"));
47
46
  var import_url = __toESM(require("url"));
47
+ var import_crypto = __toESM(require("crypto"));
48
48
  var import_tsconfig_loader = require("../third_party/tsconfig-loader");
49
49
  var import_util = require("../util");
50
50
  var import_utilsBundle = require("../utilsBundle");
package/lib/util.js CHANGED
@@ -47,7 +47,6 @@ __export(util_exports, {
47
47
  formatLocation: () => formatLocation,
48
48
  getContainedPath: () => getContainedPath,
49
49
  getPackageJsonPath: () => getPackageJsonPath,
50
- loadTestFilterFile: () => loadTestFilterFile,
51
50
  mergeObjects: () => mergeObjects,
52
51
  normalizeAndSaveAttachment: () => normalizeAndSaveAttachment,
53
52
  relativeFilePath: () => relativeFilePath,
@@ -373,22 +372,6 @@ const ansiRegex = new RegExp("([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*
373
372
  function stripAnsiEscapes(str) {
374
373
  return str.replace(ansiRegex, "");
375
374
  }
376
- async function loadTestFilterFile(filePath) {
377
- try {
378
- const data = JSON.parse(await import_fs.default.promises.readFile(filePath, "utf8"));
379
- if (!data || typeof data !== "object" || !Array.isArray(data.titlePath) || !data.titlePath.every((path2) => Array.isArray(path2)))
380
- throw new Error(`Wrong test filter file format`);
381
- const toId = (titlePath) => {
382
- const [project, file, ...titles] = titlePath;
383
- return `${project}${(0, import_utils.toPosixPath)(file)}${titles.join("")}`;
384
- };
385
- const ids = new Set(data.titlePath.map((titlePath) => toId(titlePath)));
386
- return (test) => ids.has(toId(test.titlePath()));
387
- } catch (error) {
388
- (0, import_utils.rewriteErrorMessage)(error, `Failed to read test filter file "${filePath}": ${error.message}`);
389
- throw error;
390
- }
391
- }
392
375
  // Annotate the CommonJS export names for ESM import in node:
393
376
  0 && (module.exports = {
394
377
  addSuffixToFilePath,
@@ -410,7 +393,6 @@ async function loadTestFilterFile(filePath) {
410
393
  formatLocation,
411
394
  getContainedPath,
412
395
  getPackageJsonPath,
413
- loadTestFilterFile,
414
396
  mergeObjects,
415
397
  normalizeAndSaveAttachment,
416
398
  relativeFilePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright",
3
- "version": "1.55.0-alpha-2025-08-14",
3
+ "version": "1.55.0-alpha-2025-08-15",
4
4
  "description": "A high-level API to automate web browsers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,6 +28,7 @@
28
28
  "./lib/transform/transform": "./lib/transform/transform.js",
29
29
  "./lib/internalsForTest": "./lib/internalsForTest.js",
30
30
  "./lib/plugins": "./lib/plugins/index.js",
31
+ "./lib/runner/testRunner": "./lib/runner/testRunner.js",
31
32
  "./jsx-runtime": {
32
33
  "import": "./jsx-runtime.mjs",
33
34
  "require": "./jsx-runtime.js",
@@ -56,7 +57,7 @@
56
57
  },
57
58
  "license": "Apache-2.0",
58
59
  "dependencies": {
59
- "playwright-core": "1.55.0-alpha-2025-08-14"
60
+ "playwright-core": "1.55.0-alpha-2025-08-15"
60
61
  },
61
62
  "optionalDependencies": {
62
63
  "fsevents": "2.3.2"
@@ -1,110 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var runner_exports = {};
20
- __export(runner_exports, {
21
- Runner: () => Runner
22
- });
23
- module.exports = __toCommonJS(runner_exports);
24
- var import_lastRun = require("./lastRun");
25
- var import_projectUtils = require("./projectUtils");
26
- var import_reporters = require("./reporters");
27
- var import_tasks = require("./tasks");
28
- var import_gitCommitInfoPlugin = require("../plugins/gitCommitInfoPlugin");
29
- var import_webServerPlugin = require("../plugins/webServerPlugin");
30
- var import_base = require("../reporters/base");
31
- var import_internalReporter = require("../reporters/internalReporter");
32
- var import_compilationCache = require("../transform/compilationCache");
33
- class Runner {
34
- constructor(config) {
35
- this._config = config;
36
- }
37
- async listTestFiles(projectNames) {
38
- const projects = (0, import_projectUtils.filterProjects)(this._config.projects, projectNames);
39
- const report = {
40
- projects: []
41
- };
42
- for (const project of projects) {
43
- report.projects.push({
44
- name: project.project.name,
45
- testDir: project.project.testDir,
46
- use: { testIdAttribute: project.project.use.testIdAttribute },
47
- files: await (0, import_projectUtils.collectFilesForProject)(project)
48
- });
49
- }
50
- return report;
51
- }
52
- async runAllTests() {
53
- const config = this._config;
54
- const listOnly = config.cliListOnly;
55
- (0, import_gitCommitInfoPlugin.addGitCommitInfoPlugin)(config);
56
- (0, import_webServerPlugin.webServerPluginsForConfig)(config).forEach((p) => config.plugins.push({ factory: p }));
57
- const reporters = await (0, import_reporters.createReporters)(config, listOnly ? "list" : "test", false);
58
- const lastRun = new import_lastRun.LastRunReporter(config);
59
- if (config.cliLastFailed)
60
- await lastRun.filterLastFailed();
61
- const reporter = new import_internalReporter.InternalReporter([...reporters, lastRun]);
62
- const tasks = listOnly ? [
63
- (0, import_tasks.createLoadTask)("in-process", { failOnLoadErrors: true, filterOnly: false }),
64
- (0, import_tasks.createReportBeginTask)()
65
- ] : [
66
- (0, import_tasks.createApplyRebaselinesTask)(),
67
- ...(0, import_tasks.createGlobalSetupTasks)(config),
68
- (0, import_tasks.createLoadTask)("in-process", { filterOnly: true, failOnLoadErrors: true }),
69
- ...(0, import_tasks.createRunTestsTasks)(config)
70
- ];
71
- const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), tasks, config.config.globalTimeout);
72
- await new Promise((resolve) => process.stdout.write("", () => resolve()));
73
- await new Promise((resolve) => process.stderr.write("", () => resolve()));
74
- return status;
75
- }
76
- async findRelatedTestFiles(files) {
77
- const errorReporter = (0, import_reporters.createErrorCollectingReporter)(import_base.terminalScreen);
78
- const reporter = new import_internalReporter.InternalReporter([errorReporter]);
79
- const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(this._config, reporter), [
80
- ...(0, import_tasks.createPluginSetupTasks)(this._config),
81
- (0, import_tasks.createLoadTask)("in-process", { failOnLoadErrors: true, filterOnly: false, populateDependencies: true })
82
- ]);
83
- if (status !== "passed")
84
- return { errors: errorReporter.errors(), testFiles: [] };
85
- return { testFiles: (0, import_compilationCache.affectedTestFiles)(files) };
86
- }
87
- async runDevServer() {
88
- const reporter = new import_internalReporter.InternalReporter([(0, import_reporters.createErrorCollectingReporter)(import_base.terminalScreen, true)]);
89
- const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(this._config, reporter), [
90
- ...(0, import_tasks.createPluginSetupTasks)(this._config),
91
- (0, import_tasks.createLoadTask)("in-process", { failOnLoadErrors: true, filterOnly: false }),
92
- (0, import_tasks.createStartDevServerTask)(),
93
- { title: "wait until interrupted", setup: async () => new Promise(() => {
94
- }) }
95
- ]);
96
- return { status };
97
- }
98
- async clearCache() {
99
- const reporter = new import_internalReporter.InternalReporter([(0, import_reporters.createErrorCollectingReporter)(import_base.terminalScreen, true)]);
100
- const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(this._config, reporter), [
101
- ...(0, import_tasks.createPluginSetupTasks)(this._config),
102
- (0, import_tasks.createClearCacheTask)(this._config)
103
- ]);
104
- return { status };
105
- }
106
- }
107
- // Annotate the CommonJS export names for ESM import in node:
108
- 0 && (module.exports = {
109
- Runner
110
- });