playwright 1.55.0-alpha-2025-08-13 → 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/index.js CHANGED
@@ -258,6 +258,11 @@ const playwrightFixtures = {
258
258
  if (data.apiName === "tracing.group")
259
259
  tracingGroupSteps.push(step);
260
260
  },
261
+ onApiCallRecovery: (data, error, recoveryHandlers) => {
262
+ const step = data.userData;
263
+ if (step)
264
+ recoveryHandlers.push(() => step.recoverFromStepError(error));
265
+ },
261
266
  onApiCallEnd: (data) => {
262
267
  if (data.apiName === "tracing.group")
263
268
  return;
@@ -63,6 +63,7 @@ class TestServerConnection {
63
63
  this._onStdioEmitter = new events.EventEmitter();
64
64
  this._onTestFilesChangedEmitter = new events.EventEmitter();
65
65
  this._onLoadTraceRequestedEmitter = new events.EventEmitter();
66
+ this._onRecoverFromStepErrorEmitter = new events.EventEmitter();
66
67
  this._lastId = 0;
67
68
  this._callbacks = /* @__PURE__ */ new Map();
68
69
  this._isClosed = false;
@@ -71,6 +72,7 @@ class TestServerConnection {
71
72
  this.onStdio = this._onStdioEmitter.event;
72
73
  this.onTestFilesChanged = this._onTestFilesChangedEmitter.event;
73
74
  this.onLoadTraceRequested = this._onLoadTraceRequestedEmitter.event;
75
+ this.onRecoverFromStepError = this._onRecoverFromStepErrorEmitter.event;
74
76
  this._transport = transport;
75
77
  this._transport.onmessage((data) => {
76
78
  const message = JSON.parse(data);
@@ -127,6 +129,8 @@ class TestServerConnection {
127
129
  this._onTestFilesChangedEmitter.fire(params);
128
130
  else if (method === "loadTraceRequested")
129
131
  this._onLoadTraceRequestedEmitter.fire(params);
132
+ else if (method === "recoverFromStepError")
133
+ this._onRecoverFromStepErrorEmitter.fire(params);
130
134
  }
131
135
  async initialize(params) {
132
136
  await this._sendMessage("initialize", params);
@@ -197,6 +201,9 @@ class TestServerConnection {
197
201
  async closeGracefully(params) {
198
202
  await this._sendMessage("closeGracefully", params);
199
203
  }
204
+ async resumeAfterStepError(params) {
205
+ await this._sendMessage("resumeAfterStepError", params);
206
+ }
200
207
  close() {
201
208
  try {
202
209
  this._transport.close();
@@ -234,18 +234,31 @@ class ExpectMetaInfoProxyHandler {
234
234
  infectParentStepsWithError: this._info.isSoft
235
235
  };
236
236
  const step = testInfo._addStep(stepInfo);
237
- const reportStepError = (e) => {
237
+ const reportStepError = (isAsync, e) => {
238
238
  const jestError = (0, import_matcherHint.isJestError)(e) ? e : null;
239
- const error = jestError ? new import_matcherHint.ExpectError(jestError, customMessage, stackFrames) : e;
239
+ const expectError = jestError ? new import_matcherHint.ExpectError(jestError, customMessage, stackFrames) : void 0;
240
240
  if (jestError?.matcherResult.suggestedRebaseline) {
241
241
  step.complete({ suggestedRebaseline: jestError?.matcherResult.suggestedRebaseline });
242
242
  return;
243
243
  }
244
+ const error = expectError ?? e;
244
245
  step.complete({ error });
245
- if (this._info.isSoft)
246
- testInfo._failWithError(error);
247
- else
248
- throw error;
246
+ if (!isAsync || !expectError) {
247
+ if (this._info.isSoft)
248
+ testInfo._failWithError(error);
249
+ else
250
+ throw error;
251
+ return;
252
+ }
253
+ return (async () => {
254
+ const recoveryResult = await step.recoverFromStepError(expectError);
255
+ if (recoveryResult.status === "recovered")
256
+ return recoveryResult.value;
257
+ if (this._info.isSoft)
258
+ testInfo._failWithError(expectError);
259
+ else
260
+ throw expectError;
261
+ })();
249
262
  };
250
263
  const finalizer = () => {
251
264
  step.complete({});
@@ -255,11 +268,11 @@ class ExpectMetaInfoProxyHandler {
255
268
  const callback = () => matcher.call(target, ...args);
256
269
  const result = (0, import_utils.currentZone)().with("stepZone", step).run(callback);
257
270
  if (result instanceof Promise)
258
- return result.then(finalizer).catch(reportStepError);
271
+ return result.then(finalizer).catch(reportStepError.bind(null, true));
259
272
  finalizer();
260
273
  return result;
261
274
  } catch (e) {
262
- reportStepError(e);
275
+ void reportStepError(false, e);
263
276
  }
264
277
  };
265
278
  }
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
  }