playwright 1.58.0-alpha-2025-12-04 → 1.58.0-alpha-2025-12-06

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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-143.0.7499.25-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-144.0.2-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-143.0.7499.25-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-145.0.1-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
 
@@ -10,7 +10,7 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr
10
10
  | :--- | :---: | :---: | :---: |
11
11
  | Chromium <!-- GEN:chromium-version -->143.0.7499.25<!-- 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
- | Firefox <!-- GEN:firefox-version -->144.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
13
+ | Firefox <!-- GEN:firefox-version -->145.0.1<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
14
14
 
15
15
  Headless execution is supported for all browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/intro#system-requirements) for details.
16
16
 
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,19 +17,44 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
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
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var performTask_exports = {};
20
30
  __export(performTask_exports, {
31
+ performCache: () => performCache,
21
32
  performTask: () => performTask
22
33
  });
23
34
  module.exports = __toCommonJS(performTask_exports);
35
+ var import_fs = __toESM(require("fs"));
36
+ var import_path = __toESM(require("path"));
24
37
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
25
38
  var import_mcpBundle = require("playwright-core/lib/mcpBundle");
26
39
  var import_browserContextFactory = require("../mcp/browser/browserContextFactory");
27
40
  var import_browserServerBackend = require("../mcp/browser/browserServerBackend");
28
41
  var import_config = require("../mcp/browser/config");
29
42
  var import_server = require("../mcp/sdk/server");
30
- async function performTask(context, task, options) {
43
+ const resultSchema = import_mcpBundle.z.object({
44
+ code: import_mcpBundle.z.string().optional().describe(`
45
+ Generated code to perform the task using Playwright API.
46
+ Check out the <code> blocks and combine them. Should be presented in the following form:
47
+
48
+ perform(async ({ page }) => {
49
+ // generated code here.
50
+ });
51
+ `),
52
+ error: import_mcpBundle.z.string().optional().describe("The error that occurred if execution failed.").optional()
53
+ });
54
+ async function performTask(testInfo, context, userTask, options) {
55
+ const cacheStatus = await performTaskFromCache(testInfo, context, userTask);
56
+ if (cacheStatus === "success")
57
+ return;
31
58
  const backend = new import_browserServerBackend.BrowserServerBackend(import_config.defaultConfig, (0, import_browserContextFactory.identityBrowserContextFactory)(context));
32
59
  const client = await (0, import_server.wrapInClient)(backend, { name: "Internal", version: "0.0.0" });
33
60
  const callTool = async (params) => {
@@ -44,12 +71,93 @@ async function performTask(context, task, options) {
44
71
  tools: await backend.listTools()
45
72
  });
46
73
  try {
47
- return await loop.run(task);
74
+ const result = await loop.run(userTask, { resultSchema: (0, import_mcpBundle.zodToJsonSchema)(resultSchema) });
75
+ if (result.code)
76
+ await updatePerformFile(testInfo, userTask, result.code, options);
48
77
  } finally {
49
78
  await client.close();
50
79
  }
51
80
  }
81
+ async function updatePerformFile(testInfo, userTask, taskCode, options) {
82
+ const relativeFile = import_path.default.relative(testInfo.project.testDir, testInfo.file);
83
+ const promptCacheFile = testInfo.file.replace(".spec.ts", ".cache.ts");
84
+ const testTitle = testInfo.title;
85
+ const loop = new import_mcpBundle.Loop(options.provider ?? "github", {
86
+ model: options.model ?? "claude-sonnet-4.5",
87
+ reasoning: options.reasoning,
88
+ temperature: options.temperature,
89
+ maxTokens: options.maxTokens,
90
+ summarize: true,
91
+ debug: import_utilsBundle.debug,
92
+ callTool: async () => ({ content: [] }),
93
+ tools: []
94
+ });
95
+ const resultSchema2 = import_mcpBundle.z.object({
96
+ code: import_mcpBundle.z.string().optional().describe(`
97
+ Generated code with all the perofrm routines combined or updated into the following format:
98
+
99
+ import { performCache } from '@playwright/test';
100
+
101
+ performCache({
102
+ file: 'tests/page/perform-task.spec.ts',
103
+ test: 'perform task',
104
+ task: 'Click the learn more button',
105
+ code: async ({ page }) => {
106
+ await page.getByRole('link', { name: 'Learn more' }).click();
107
+ },
108
+ });
109
+ `)
110
+ });
111
+ const existingCode = await import_fs.default.promises.readFile(promptCacheFile, "utf8").catch(() => "");
112
+ const task = `
113
+ - Create or update a perform file to include performCache block for the given task and code.
114
+ - Dedupe items with the same file, test, and task.
115
+ - Should produce code in the following format
116
+
117
+ import { performCache } from '@playwright/test';
118
+
119
+ performCache({
120
+ file: '<file>',
121
+ test: '<test>',
122
+ task: '<task>',
123
+ code: async ({ page }) => {
124
+ <code>
125
+ },
126
+ });
127
+
128
+ performCache({
129
+ ...
130
+
131
+ ## Params for the new or updated performCache block
132
+ <file-content>${existingCode}</file-content>
133
+ <file>${relativeFile}</file>
134
+ <test>${testTitle}</test>
135
+ <task>${userTask}</task>
136
+ <code>${taskCode}</code>
137
+ `;
138
+ const result = await loop.run(task, { resultSchema: (0, import_mcpBundle.zodToJsonSchema)(resultSchema2) });
139
+ if (result.code)
140
+ await import_fs.default.promises.writeFile(promptCacheFile, result.code);
141
+ }
142
+ const performCacheMap = /* @__PURE__ */ new Map();
143
+ function performCache(entry) {
144
+ performCacheMap.set(JSON.stringify({ ...entry, code: void 0 }), entry);
145
+ }
146
+ async function performTaskFromCache(testInfo, context, userTask) {
147
+ const relativeFile = import_path.default.relative(testInfo.project.testDir, testInfo.file);
148
+ const key = JSON.stringify({ file: relativeFile, test: testInfo.title, task: userTask });
149
+ const entry = performCacheMap.get(key);
150
+ if (!entry)
151
+ return "cache-miss";
152
+ try {
153
+ await entry.code({ page: context.pages()[0] });
154
+ return "success";
155
+ } catch (error) {
156
+ return error;
157
+ }
158
+ }
52
159
  // Annotate the CommonJS export names for ESM import in node:
53
160
  0 && (module.exports = {
161
+ performCache,
54
162
  performTask
55
163
  });
package/lib/index.js CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  expect: () => import_expect.expect,
34
34
  mergeExpects: () => import_expect2.mergeExpects,
35
35
  mergeTests: () => import_testType2.mergeTests,
36
+ performCache: () => import_performTask2.performCache,
36
37
  test: () => test
37
38
  });
38
39
  module.exports = __toCommonJS(index_exports);
@@ -48,6 +49,7 @@ var import_expect = require("./matchers/expect");
48
49
  var import_configLoader = require("./common/configLoader");
49
50
  var import_testType2 = require("./common/testType");
50
51
  var import_expect2 = require("./matchers/expect");
52
+ var import_performTask2 = require("./agents/performTask");
51
53
  const _baseTest = import_testType.rootTestType.test;
52
54
  (0, import_utils.setBoxedStackPrefixes)([import_path.default.dirname(require.resolve("../package.json"))]);
53
55
  if (process["__pw_initiator__"]) {
@@ -417,9 +419,9 @@ const playwrightFixtures = {
417
419
  await request.dispose();
418
420
  }
419
421
  },
420
- _perform: async ({ context }, use) => {
422
+ _perform: async ({ context }, use, testInfo) => {
421
423
  await use(async (task, options) => {
422
- await (0, import_performTask.performTask)(context, task, options ?? {});
424
+ await (0, import_performTask.performTask)(testInfo, context, task, options ?? {});
423
425
  });
424
426
  }
425
427
  };
@@ -684,5 +686,6 @@ const test = _baseTest.extend(playwrightFixtures);
684
686
  expect,
685
687
  mergeExpects,
686
688
  mergeTests,
689
+ performCache,
687
690
  test
688
691
  });
@@ -70,10 +70,6 @@ class TeleReporterReceiver {
70
70
  this._onAttach(params.testId, params.resultId, params.attachments);
71
71
  return;
72
72
  }
73
- if (method === "onTestError") {
74
- this._onTestError(params.testId, params.resultId, params.error);
75
- return;
76
- }
77
73
  if (method === "onStepEnd") {
78
74
  this._onStepEnd(params.testId, params.resultId, params.step);
79
75
  return;
@@ -127,10 +123,8 @@ class TeleReporterReceiver {
127
123
  const result = test.results.find((r) => r._id === payload.id);
128
124
  result.duration = payload.duration;
129
125
  result.status = payload.status;
130
- if (!!payload.errors) {
131
- result.errors = payload.errors;
132
- result.error = result.errors[0];
133
- }
126
+ result.errors = payload.errors;
127
+ result.error = result.errors?.[0];
134
128
  if (!!payload.attachments)
135
129
  result.attachments = this._parseAttachments(payload.attachments);
136
130
  if (payload.annotations) {
@@ -173,12 +167,6 @@ class TeleReporterReceiver {
173
167
  body: a.base64 && globalThis.Buffer ? Buffer.from(a.base64, "base64") : void 0
174
168
  })));
175
169
  }
176
- _onTestError(testId, resultId, error) {
177
- const test = this._tests.get(testId);
178
- const result = test.results.find((r) => r._id === resultId);
179
- result.errors.push(error);
180
- result.error = result.errors[0];
181
- }
182
170
  _onError(error) {
183
171
  this._reporter.onError?.(error);
184
172
  }
@@ -216,6 +216,8 @@ class PersistentContextFactory {
216
216
  });
217
217
  await afterClose();
218
218
  this._userDataDirs.delete(userDataDir);
219
+ if (process.env.PWMCP_PROFILES_DIR_FOR_TEST && userDataDir.startsWith(process.env.PWMCP_PROFILES_DIR_FOR_TEST))
220
+ await import_fs.default.promises.rm(userDataDir, { recursive: true }).catch(import_log.logUnhandledError);
219
221
  (0, import_log.testDebug)("close browser context complete (persistent)");
220
222
  }
221
223
  async _createUserDataDir(clientInfo) {
@@ -32,6 +32,7 @@ __export(config_exports, {
32
32
  configFromCLIOptions: () => configFromCLIOptions,
33
33
  defaultConfig: () => defaultConfig,
34
34
  dotenvFileLoader: () => dotenvFileLoader,
35
+ enumParser: () => enumParser,
35
36
  headerParser: () => headerParser,
36
37
  numberParser: () => numberParser,
37
38
  outputDir: () => outputDir,
@@ -61,6 +62,9 @@ const defaultConfig = {
61
62
  viewport: null
62
63
  }
63
64
  },
65
+ console: {
66
+ level: "info"
67
+ },
64
68
  network: {
65
69
  allowedOrigins: void 0,
66
70
  blockedOrigins: void 0
@@ -182,6 +186,9 @@ function configFromCLIOptions(cliOptions) {
182
186
  allowedHosts: cliOptions.allowedHosts
183
187
  },
184
188
  capabilities: cliOptions.caps,
189
+ console: {
190
+ level: cliOptions.consoleLevel
191
+ },
185
192
  network: {
186
193
  allowedOrigins: cliOptions.allowedOrigins,
187
194
  blockedOrigins: cliOptions.blockedOrigins
@@ -213,6 +220,8 @@ function configFromEnv() {
213
220
  options.cdpEndpoint = envToString(process.env.PLAYWRIGHT_MCP_CDP_ENDPOINT);
214
221
  options.cdpHeader = headerParser(process.env.PLAYWRIGHT_MCP_CDP_HEADERS, {});
215
222
  options.config = envToString(process.env.PLAYWRIGHT_MCP_CONFIG);
223
+ if (process.env.PLAYWRIGHT_MCP_CONSOLE_LEVEL)
224
+ options.consoleLevel = enumParser("--console-level", ["error", "warning", "info", "debug"], process.env.PLAYWRIGHT_MCP_CONSOLE_LEVEL);
216
225
  options.device = envToString(process.env.PLAYWRIGHT_MCP_DEVICE);
217
226
  options.executablePath = envToString(process.env.PLAYWRIGHT_MCP_EXECUTABLE_PATH);
218
227
  options.grantPermissions = commaSeparatedList(process.env.PLAYWRIGHT_MCP_GRANT_PERMISSIONS);
@@ -226,8 +235,8 @@ function configFromEnv() {
226
235
  if (initScript)
227
236
  options.initScript = [initScript];
228
237
  options.isolated = envToBoolean(process.env.PLAYWRIGHT_MCP_ISOLATED);
229
- if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES === "omit")
230
- options.imageResponses = "omit";
238
+ if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES)
239
+ options.imageResponses = enumParser("--image-responses", ["allow", "omit"], process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES);
231
240
  options.sandbox = envToBoolean(process.env.PLAYWRIGHT_MCP_SANDBOX);
232
241
  options.outputDir = envToString(process.env.PLAYWRIGHT_MCP_OUTPUT_DIR);
233
242
  options.port = numberParser(process.env.PLAYWRIGHT_MCP_PORT);
@@ -306,6 +315,10 @@ function mergeConfig(base, overrides) {
306
315
  ...pickDefined(base),
307
316
  ...pickDefined(overrides),
308
317
  browser,
318
+ console: {
319
+ ...pickDefined(base.console),
320
+ ...pickDefined(overrides.console)
321
+ },
309
322
  network: {
310
323
  ...pickDefined(base.network),
311
324
  ...pickDefined(overrides.network)
@@ -369,6 +382,11 @@ function headerParser(arg, previous) {
369
382
  result[name] = value;
370
383
  return result;
371
384
  }
385
+ function enumParser(name, options, value) {
386
+ if (!options.includes(value))
387
+ throw new Error(`Invalid ${name}: ${value}. Valid values are: ${options.join(", ")}`);
388
+ return value;
389
+ }
372
390
  function envToBoolean(value) {
373
391
  if (value === "true" || value === "1")
374
392
  return true;
@@ -392,6 +410,7 @@ function sanitizeForFilePath(s) {
392
410
  configFromCLIOptions,
393
411
  defaultConfig,
394
412
  dotenvFileLoader,
413
+ enumParser,
395
414
  headerParser,
396
415
  numberParser,
397
416
  outputDir,
@@ -173,9 +173,9 @@ class Tab extends import_events.EventEmitter {
173
173
  }
174
174
  await this.waitForLoadState("load", { timeout: 5e3 });
175
175
  }
176
- async consoleMessages(type) {
176
+ async consoleMessages(level) {
177
177
  await this._initializedPromise;
178
- return this._consoleMessages.filter((message) => type ? message.type === type : true);
178
+ return this._consoleMessages.filter((message) => shouldIncludeMessage(level, message.type));
179
179
  }
180
180
  async requests() {
181
181
  await this._initializedPromise;
@@ -197,7 +197,7 @@ class Tab extends import_events.EventEmitter {
197
197
  };
198
198
  });
199
199
  if (tabSnapshot) {
200
- tabSnapshot.consoleMessages = this._recentConsoleMessages;
200
+ tabSnapshot.consoleMessages = this._recentConsoleMessages.filter((message) => shouldIncludeMessage(this.context.config.console.level, message.type));
201
201
  this._recentConsoleMessages = [];
202
202
  }
203
203
  this._needsFullSnapshot = !tabSnapshot;
@@ -287,6 +287,40 @@ function renderModalStates(modalStates) {
287
287
  result.push(`- [${state.description}]: can be handled by the "${state.clearedBy}" tool`);
288
288
  return result;
289
289
  }
290
+ const consoleMessageLevels = ["error", "warning", "info", "debug"];
291
+ function shouldIncludeMessage(thresholdLevel, type) {
292
+ const messageLevel = consoleLevelForMessageType(type);
293
+ return consoleMessageLevels.indexOf(messageLevel) <= consoleMessageLevels.indexOf(thresholdLevel);
294
+ }
295
+ function consoleLevelForMessageType(type) {
296
+ switch (type) {
297
+ case "assert":
298
+ case "error":
299
+ return "error";
300
+ case "warning":
301
+ return "warning";
302
+ case "count":
303
+ case "dir":
304
+ case "dirxml":
305
+ case "info":
306
+ case "log":
307
+ case "table":
308
+ case "time":
309
+ case "timeEnd":
310
+ return "info";
311
+ case "clear":
312
+ case "debug":
313
+ case "endGroup":
314
+ case "profile":
315
+ case "profileEnd":
316
+ case "startGroup":
317
+ case "startGroupCollapsed":
318
+ case "trace":
319
+ return "debug";
320
+ default:
321
+ return "info";
322
+ }
323
+ }
290
324
  const tabSymbol = Symbol("tabSymbol");
291
325
  // Annotate the CommonJS export names for ESM import in node:
292
326
  0 && (module.exports = {
@@ -30,12 +30,12 @@ const console = (0, import_tool.defineTabTool)({
30
30
  title: "Get console messages",
31
31
  description: "Returns all console messages",
32
32
  inputSchema: import_mcpBundle.z.object({
33
- onlyErrors: import_mcpBundle.z.boolean().optional().describe("Only return error messages")
33
+ level: import_mcpBundle.z.enum(["error", "warning", "info", "debug"]).default("info").describe('Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".')
34
34
  }),
35
35
  type: "readOnly"
36
36
  },
37
37
  handle: async (tab, params, response) => {
38
- const messages = await tab.consoleMessages(params.onlyErrors ? "error" : void 0);
38
+ const messages = await tab.consoleMessages(params.level);
39
39
  messages.map((message) => response.addResult(message.toString()));
40
40
  }
41
41
  });
@@ -29,24 +29,30 @@ const requests = (0, import_tool.defineTabTool)({
29
29
  name: "browser_network_requests",
30
30
  title: "List network requests",
31
31
  description: "Returns all network requests since loading the page",
32
- inputSchema: import_mcpBundle.z.object({}),
32
+ inputSchema: import_mcpBundle.z.object({
33
+ includeStatic: import_mcpBundle.z.boolean().default(false).describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.")
34
+ }),
33
35
  type: "readOnly"
34
36
  },
35
37
  handle: async (tab, params, response) => {
36
38
  const requests2 = await tab.requests();
37
- for (const request of requests2)
38
- response.addResult(await renderRequest(request));
39
+ for (const request of requests2) {
40
+ const rendered = await renderRequest(request, params.includeStatic);
41
+ if (rendered)
42
+ response.addResult(rendered);
43
+ }
39
44
  }
40
45
  });
41
- async function renderRequest(request) {
46
+ async function renderRequest(request, includeStatic) {
47
+ const response = request._hasResponse ? await request.response() : void 0;
48
+ const isStaticRequest = ["document", "stylesheet", "image", "media", "font", "script", "manifest"].includes(request.resourceType());
49
+ const isSuccessfulRequest = !response || response.status() < 400;
50
+ if (isStaticRequest && isSuccessfulRequest && !includeStatic)
51
+ return void 0;
42
52
  const result = [];
43
53
  result.push(`[${request.method().toUpperCase()}] ${request.url()}`);
44
- const hasResponse = request._hasResponse;
45
- if (hasResponse) {
46
- const response = await request.response();
47
- if (response)
48
- result.push(`=> [${response.status()}] ${response.statusText()}`);
49
- }
54
+ if (response)
55
+ result.push(`=> [${response.status()}] ${response.statusText()}`);
50
56
  return result.join(" ");
51
57
  }
52
58
  var network_default = [
@@ -42,7 +42,7 @@ var import_proxyBackend = require("./sdk/proxyBackend");
42
42
  var import_browserServerBackend = require("./browser/browserServerBackend");
43
43
  var import_extensionContextFactory = require("./extension/extensionContextFactory");
44
44
  function decorateCommand(command, version) {
45
- command.option("--allowed-hosts <hosts...>", "comma-separated list of hosts this server is allowed to serve from. Defaults to the host the server is bound to. Pass '*' to disable the host check.", import_config.commaSeparatedList).option("--allowed-origins <origins>", "semicolon-separated list of TRUSTED origins to allow the browser to request. Default is to allow all.\nImportant: *does not* serve as a security boundary and *does not* affect redirects. ", import_config.semicolonSeparatedList).option("--blocked-origins <origins>", "semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.\nImportant: *does not* serve as a security boundary and *does not* affect redirects.", import_config.semicolonSeparatedList).option("--block-service-workers", "block service workers").option("--browser <browser>", "browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.").option("--caps <caps>", "comma-separated list of additional capabilities to enable, possible values: vision, pdf.", import_config.commaSeparatedList).option("--cdp-endpoint <endpoint>", "CDP endpoint to connect to.").option("--cdp-header <headers...>", "CDP headers to send with the connect request, multiple can be specified.", import_config.headerParser).option("--config <path>", "path to the configuration file.").option("--device <device>", 'device to emulate, for example: "iPhone 15"').option("--executable-path <path>", "path to the browser executable.").option("--extension", 'Connect to a running browser instance (Edge/Chrome only). Requires the "Playwright MCP Bridge" browser extension to be installed.').option("--grant-permissions <permissions...>", 'List of permissions to grant to the browser context, for example "geolocation", "clipboard-read", "clipboard-write".', import_config.commaSeparatedList).option("--headless", "run browser in headless mode, headed by default").option("--host <host>", "host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.").option("--ignore-https-errors", "ignore https errors").option("--init-page <path...>", "path to TypeScript file to evaluate on Playwright page object").option("--init-script <path...>", "path to JavaScript file to add as an initialization script. The script will be evaluated in every page before any of the page's scripts. Can be specified multiple times.").option("--isolated", "keep the browser profile in memory, do not save it to disk.").option("--image-responses <mode>", 'whether to send image responses to the client. Can be "allow" or "omit", Defaults to "allow".').option("--no-sandbox", "disable the sandbox for all process types that are normally sandboxed.").option("--output-dir <path>", "path to the directory for output files.").option("--port <port>", "port to listen on for SSE transport.").option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--save-session", "Whether to save the Playwright MCP session into the output directory.").option("--save-trace", "Whether to save the Playwright Trace of the session into the output directory.").option("--save-video <size>", 'Whether to save the video of the session into the output directory. For example "--save-video=800x600"', import_config.resolutionParser.bind(null, "--save-video")).option("--secrets <path>", "path to a file containing secrets in the dotenv format", import_config.dotenvFileLoader).option("--shared-browser-context", "reuse the same browser context between all connected HTTP clients.").option("--snapshot-mode <mode>", 'when taking snapshots for responses, specifies the mode to use. Can be "incremental", "full", or "none". Default is incremental.').option("--storage-state <path>", "path to the storage state file for isolated sessions.").option("--test-id-attribute <attribute>", 'specify the attribute to use for test ids, defaults to "data-testid"').option("--timeout-action <timeout>", "specify action timeout in milliseconds, defaults to 5000ms", import_config.numberParser).option("--timeout-navigation <timeout>", "specify navigation timeout in milliseconds, defaults to 60000ms", import_config.numberParser).option("--user-agent <ua string>", "specify user agent string").option("--user-data-dir <path>", "path to the user data directory. If not specified, a temporary directory will be created.").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280x720"', import_config.resolutionParser.bind(null, "--viewport-size")).addOption(new import_utilsBundle.ProgramOption("--connect-tool", "Allow to switch between different browser connection methods.").hideHelp()).addOption(new import_utilsBundle.ProgramOption("--vision", "Legacy option, use --caps=vision instead").hideHelp()).action(async (options) => {
45
+ command.option("--allowed-hosts <hosts...>", "comma-separated list of hosts this server is allowed to serve from. Defaults to the host the server is bound to. Pass '*' to disable the host check.", import_config.commaSeparatedList).option("--allowed-origins <origins>", "semicolon-separated list of TRUSTED origins to allow the browser to request. Default is to allow all.\nImportant: *does not* serve as a security boundary and *does not* affect redirects. ", import_config.semicolonSeparatedList).option("--blocked-origins <origins>", "semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.\nImportant: *does not* serve as a security boundary and *does not* affect redirects.", import_config.semicolonSeparatedList).option("--block-service-workers", "block service workers").option("--browser <browser>", "browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.").option("--caps <caps>", "comma-separated list of additional capabilities to enable, possible values: vision, pdf.", import_config.commaSeparatedList).option("--cdp-endpoint <endpoint>", "CDP endpoint to connect to.").option("--cdp-header <headers...>", "CDP headers to send with the connect request, multiple can be specified.", import_config.headerParser).option("--config <path>", "path to the configuration file.").option("--console-level <level>", 'level of console messages to return: "error", "warning", "info", "debug". Each level includes the messages of more severe levels.', import_config.enumParser.bind(null, "--console-level", ["error", "warning", "info", "debug"])).option("--device <device>", 'device to emulate, for example: "iPhone 15"').option("--executable-path <path>", "path to the browser executable.").option("--extension", 'Connect to a running browser instance (Edge/Chrome only). Requires the "Playwright MCP Bridge" browser extension to be installed.').option("--grant-permissions <permissions...>", 'List of permissions to grant to the browser context, for example "geolocation", "clipboard-read", "clipboard-write".', import_config.commaSeparatedList).option("--headless", "run browser in headless mode, headed by default").option("--host <host>", "host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.").option("--ignore-https-errors", "ignore https errors").option("--init-page <path...>", "path to TypeScript file to evaluate on Playwright page object").option("--init-script <path...>", "path to JavaScript file to add as an initialization script. The script will be evaluated in every page before any of the page's scripts. Can be specified multiple times.").option("--isolated", "keep the browser profile in memory, do not save it to disk.").option("--image-responses <mode>", 'whether to send image responses to the client. Can be "allow" or "omit", Defaults to "allow".', import_config.enumParser.bind(null, "--image-responses", ["allow", "omit"])).option("--no-sandbox", "disable the sandbox for all process types that are normally sandboxed.").option("--output-dir <path>", "path to the directory for output files.").option("--port <port>", "port to listen on for SSE transport.").option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--save-session", "Whether to save the Playwright MCP session into the output directory.").option("--save-trace", "Whether to save the Playwright Trace of the session into the output directory.").option("--save-video <size>", 'Whether to save the video of the session into the output directory. For example "--save-video=800x600"', import_config.resolutionParser.bind(null, "--save-video")).option("--secrets <path>", "path to a file containing secrets in the dotenv format", import_config.dotenvFileLoader).option("--shared-browser-context", "reuse the same browser context between all connected HTTP clients.").option("--snapshot-mode <mode>", 'when taking snapshots for responses, specifies the mode to use. Can be "incremental", "full", or "none". Default is incremental.').option("--storage-state <path>", "path to the storage state file for isolated sessions.").option("--test-id-attribute <attribute>", 'specify the attribute to use for test ids, defaults to "data-testid"').option("--timeout-action <timeout>", "specify action timeout in milliseconds, defaults to 5000ms", import_config.numberParser).option("--timeout-navigation <timeout>", "specify navigation timeout in milliseconds, defaults to 60000ms", import_config.numberParser).option("--user-agent <ua string>", "specify user agent string").option("--user-data-dir <path>", "path to the user data directory. If not specified, a temporary directory will be created.").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280x720"', import_config.resolutionParser.bind(null, "--viewport-size")).addOption(new import_utilsBundle.ProgramOption("--connect-tool", "Allow to switch between different browser connection methods.").hideHelp()).addOption(new import_utilsBundle.ProgramOption("--vision", "Legacy option, use --caps=vision instead").hideHelp()).action(async (options) => {
46
46
  (0, import_watchdog.setupExitWatchdog)();
47
47
  if (options.vision) {
48
48
  console.error("The --vision option is deprecated, use --caps=vision instead");
@@ -74,7 +74,7 @@ async function generatePausedMessage(testInfo, context) {
74
74
  `- Page Title: ${await page.title()}`.trim()
75
75
  );
76
76
  let console = testInfo.errors.length ? await import_tab.Tab.collectConsoleMessages(page) : [];
77
- console = console.filter((msg) => !msg.type || msg.type === "error");
77
+ console = console.filter((msg) => msg.type === "error");
78
78
  if (console.length) {
79
79
  lines.push("- Console Messages:");
80
80
  for (const message of console)
@@ -66,11 +66,8 @@ class InternalReporter {
66
66
  onStdErr(chunk, test, result) {
67
67
  this._reporter.onStdErr?.(chunk, test, result);
68
68
  }
69
- onTestError(test, result, error) {
70
- addLocationAndSnippetToError(this._config, error, test.location.file);
71
- this._reporter.onTestError?.(test, result, error);
72
- }
73
69
  onTestEnd(test, result) {
70
+ this._addSnippetToTestErrors(test, result);
74
71
  this._reporter.onTestEnd?.(test, result);
75
72
  }
76
73
  async onEnd(result) {
@@ -87,20 +84,27 @@ class InternalReporter {
87
84
  await this._reporter.onExit?.();
88
85
  }
89
86
  onError(error) {
90
- addLocationAndSnippetToError(this._config, error, void 0);
87
+ addLocationAndSnippetToError(this._config, error);
91
88
  this._reporter.onError?.(error);
92
89
  }
93
90
  onStepBegin(test, result, step) {
94
91
  this._reporter.onStepBegin?.(test, result, step);
95
92
  }
96
93
  onStepEnd(test, result, step) {
97
- if (step.error)
98
- addLocationAndSnippetToError(this._config, step.error, test.location.file);
94
+ this._addSnippetToStepError(test, step);
99
95
  this._reporter.onStepEnd?.(test, result, step);
100
96
  }
101
97
  printsToStdio() {
102
98
  return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;
103
99
  }
100
+ _addSnippetToTestErrors(test, result) {
101
+ for (const error of result.errors)
102
+ addLocationAndSnippetToError(this._config, error, test.location.file);
103
+ }
104
+ _addSnippetToStepError(test, step) {
105
+ if (step.error)
106
+ addLocationAndSnippetToError(this._config, step.error, test.location.file);
107
+ }
104
108
  }
105
109
  function addLocationAndSnippetToError(config, error, file) {
106
110
  if (error.stack && !error.location)
@@ -342,7 +342,6 @@ class IdsPatcher {
342
342
  case "onProject":
343
343
  this._onProject(params.project);
344
344
  return;
345
- case "onTestError":
346
345
  case "onAttach":
347
346
  case "onTestBegin":
348
347
  case "onStepBegin":
@@ -424,7 +423,7 @@ class PathSeparatorPatcher {
424
423
  test.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
425
424
  const testResult = jsonEvent.params.result;
426
425
  testResult.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
427
- testResult.errors?.forEach((error) => this._updateErrorLocations(error));
426
+ testResult.errors.forEach((error) => this._updateErrorLocations(error));
428
427
  (testResult.attachments ?? []).forEach((attachment) => {
429
428
  if (attachment.path)
430
429
  attachment.path = this._updatePath(attachment.path);
@@ -442,10 +441,6 @@ class PathSeparatorPatcher {
442
441
  step.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
443
442
  return;
444
443
  }
445
- if (jsonEvent.method === "onTestError") {
446
- this._updateErrorLocations(jsonEvent.params.error);
447
- return;
448
- }
449
444
  if (jsonEvent.method === "onAttach") {
450
445
  const attach = jsonEvent.params;
451
446
  attach.attachments.forEach((attachment) => {
@@ -48,10 +48,6 @@ class Multiplexer {
48
48
  for (const reporter of this._reporters)
49
49
  wrap(() => reporter.onStdErr?.(chunk, test, result));
50
50
  }
51
- onTestError(test, result, error) {
52
- for (const reporter of this._reporters)
53
- wrap(() => reporter.onTestError?.(test, result, error));
54
- }
55
51
  onTestEnd(test, result) {
56
52
  for (const reporter of this._reporters)
57
53
  wrap(() => reporter.onTestEnd?.(test, result));
@@ -66,16 +66,6 @@ class TeleReporterEmitter {
66
66
  }
67
67
  });
68
68
  }
69
- onTestError(test, result, error) {
70
- this._messageSink({
71
- method: "onTestError",
72
- params: {
73
- testId: test.id,
74
- resultId: result[this._idSymbol],
75
- error
76
- }
77
- });
78
- }
79
69
  onTestEnd(test, result) {
80
70
  const testEnd = {
81
71
  testId: test.id,
@@ -235,6 +225,7 @@ class TeleReporterEmitter {
235
225
  id: result[this._idSymbol],
236
226
  duration: result.duration,
237
227
  status: result.status,
228
+ errors: result.errors,
238
229
  annotations: result.annotations?.length ? this._relativeAnnotationLocations(result.annotations) : void 0
239
230
  };
240
231
  }
@@ -243,6 +243,7 @@ class JobDispatcher {
243
243
  _onTestEnd(params) {
244
244
  if (this._failureTracker.hasReachedMaxFailures()) {
245
245
  params.status = "interrupted";
246
+ params.errors = [];
246
247
  }
247
248
  const data = this._dataByTestId.get(params.testId);
248
249
  if (!data) {
@@ -252,6 +253,8 @@ class JobDispatcher {
252
253
  this._remainingByTestId.delete(params.testId);
253
254
  const { result, test } = data;
254
255
  result.duration = params.duration;
256
+ result.errors = params.errors;
257
+ result.error = result.errors[0];
255
258
  result.status = params.status;
256
259
  result.annotations = params.annotations;
257
260
  test.annotations = [...params.annotations];
@@ -338,20 +341,6 @@ class JobDispatcher {
338
341
  this._reporter.onStdErr?.("Internal error: step id not found: " + params.stepId);
339
342
  }
340
343
  }
341
- _onTestErrors(params) {
342
- if (this._failureTracker.hasReachedMaxFailures()) {
343
- return;
344
- }
345
- const data = this._dataByTestId.get(params.testId);
346
- if (!data)
347
- return;
348
- const { test, result } = data;
349
- for (const error of params.errors) {
350
- result.errors.push(error);
351
- result.error = result.errors[0];
352
- this._reporter.onTestError?.(test, result, error);
353
- }
354
- }
355
344
  _failTestWithErrors(test, errors) {
356
345
  const runData = this._dataByTestId.get(test.id);
357
346
  let result;
@@ -361,11 +350,8 @@ class JobDispatcher {
361
350
  result = test._appendTestResult();
362
351
  this._reporter.onTestBegin?.(test, result);
363
352
  }
364
- for (const error of errors) {
365
- result.errors.push(error);
366
- result.error = result.errors[0];
367
- this._reporter.onTestError?.(test, result, error);
368
- }
353
+ result.errors = [...errors];
354
+ result.error = result.errors[0];
369
355
  result.status = errors.length ? "failed" : "skipped";
370
356
  this._reportTestEnd(test, result);
371
357
  this._failedTests.add(test);
@@ -466,32 +452,29 @@ class JobDispatcher {
466
452
  import_utils.eventsHelper.addEventListener(worker, "stepBegin", this._onStepBegin.bind(this)),
467
453
  import_utils.eventsHelper.addEventListener(worker, "stepEnd", this._onStepEnd.bind(this)),
468
454
  import_utils.eventsHelper.addEventListener(worker, "attach", this._onAttach.bind(this)),
469
- import_utils.eventsHelper.addEventListener(worker, "testErrors", this._onTestErrors.bind(this)),
470
455
  import_utils.eventsHelper.addEventListener(worker, "testPaused", this._onTestPaused.bind(this, worker)),
471
456
  import_utils.eventsHelper.addEventListener(worker, "done", this._onDone.bind(this)),
472
457
  import_utils.eventsHelper.addEventListener(worker, "exit", this.onExit.bind(this))
473
458
  ];
474
459
  }
475
460
  _onTestPaused(worker, params) {
476
- const data = this._dataByTestId.get(params.testId);
477
- if (!data)
478
- return;
479
- const { test, result } = data;
480
461
  const sendMessage = async (message) => {
481
462
  try {
482
463
  if (this.jobResult.isDone())
483
464
  throw new Error("Test has already stopped");
484
465
  const response = await worker.sendCustomMessage({ testId: params.testId, request: message.request });
485
466
  if (response.error)
486
- (0, import_internalReporter.addLocationAndSnippetToError)(this._config.config, response.error, test.location.file);
467
+ (0, import_internalReporter.addLocationAndSnippetToError)(this._config.config, response.error);
487
468
  return response;
488
469
  } catch (e) {
489
470
  const error = (0, import_util.serializeError)(e);
490
- (0, import_internalReporter.addLocationAndSnippetToError)(this._config.config, error, test.location.file);
471
+ (0, import_internalReporter.addLocationAndSnippetToError)(this._config.config, error);
491
472
  return { response: void 0, error };
492
473
  }
493
474
  };
494
- this._failureTracker.onTestPaused?.({ errors: result.errors, sendMessage });
475
+ for (const error of params.errors)
476
+ (0, import_internalReporter.addLocationAndSnippetToError)(this._config.config, error);
477
+ this._failureTracker.onTestPaused?.({ ...params, sendMessage });
495
478
  }
496
479
  skipWholeJob() {
497
480
  const allTestsSkipped = this.job.tests.every((test) => test.expectedStatus === "skipped");
@@ -383,8 +383,7 @@ async function runAllTestsWithConfig(config) {
383
383
  (0, import_tasks.createLoadTask)("in-process", { filterOnly: true, failOnLoadErrors: true }),
384
384
  ...(0, import_tasks.createRunTestsTasks)(config)
385
385
  ];
386
- const testRun = new import_tasks.TestRun(config, reporter, { pauseAtEnd: config.configCLIOverrides.debug, pauseOnError: config.configCLIOverrides.debug });
387
- const status = await (0, import_tasks.runTasks)(testRun, tasks, config.config.globalTimeout);
386
+ const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), tasks, config.config.globalTimeout);
388
387
  await new Promise((resolve) => process.stdout.write("", () => resolve()));
389
388
  await new Promise((resolve) => process.stderr.write("", () => resolve()));
390
389
  return status;
@@ -42,9 +42,8 @@ var import_util = require("../util");
42
42
  var import_testTracing = require("./testTracing");
43
43
  var import_util2 = require("./util");
44
44
  var import_transform = require("../transform/transform");
45
- var import_babelHighlightUtils = require("../transform/babelHighlightUtils");
46
45
  class TestInfoImpl {
47
- constructor(configInternal, projectInternal, workerParams, test, retry, onStepBegin, onStepEnd, onAttach, onErrors, onTestPaused) {
46
+ constructor(configInternal, projectInternal, workerParams, test, retry, onStepBegin, onStepEnd, onAttach, onTestPaused) {
48
47
  this._snapshotNames = { lastAnonymousSnapshotIndex: 0, lastNamedSnapshotIndex: {} };
49
48
  this._ariaSnapshotNames = { lastAnonymousSnapshotIndex: 0, lastNamedSnapshotIndex: {} };
50
49
  this._interruptedPromise = new import_utils.ManualPromise();
@@ -60,12 +59,10 @@ class TestInfoImpl {
60
59
  this.status = "passed";
61
60
  this.snapshotSuffix = "";
62
61
  this.errors = [];
63
- this._reportedErrorCount = 0;
64
62
  this.testId = test?.id ?? "";
65
63
  this._onStepBegin = onStepBegin;
66
64
  this._onStepEnd = onStepEnd;
67
65
  this._onAttach = onAttach;
68
- this._onErrors = onErrors;
69
66
  this._onTestPaused = onTestPaused;
70
67
  this._startTime = (0, import_utils.monotonicTime)();
71
68
  this._startWallTime = Date.now();
@@ -341,32 +338,11 @@ ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
341
338
  async _didFinishTestFunction() {
342
339
  const shouldPause = this._workerParams.pauseAtEnd && !this._isFailure() || this._workerParams.pauseOnError && this._isFailure();
343
340
  if (shouldPause) {
344
- const location = (this._isFailure() ? this._errorLocation() : await this._testEndLocation()) ?? { file: this.file, line: this.line, column: this.column };
345
- this._emitErrors();
346
- this._onTestPaused({ testId: this.testId });
347
- await this._runAsStep({ title: this._isFailure() ? "Paused on Error" : "Paused at End", category: "test.step", location }, async () => {
348
- await this._interruptedPromise;
349
- });
341
+ this._onTestPaused({ testId: this.testId, errors: this._isFailure() ? this.errors : [] });
342
+ await this._interruptedPromise;
350
343
  }
351
344
  await this._onDidFinishTestFunctionCallback?.();
352
345
  }
353
- _emitErrors() {
354
- const errors = this.errors.slice(this._reportedErrorCount);
355
- this._reportedErrorCount = Math.max(this._reportedErrorCount, this.errors.length);
356
- if (errors.length)
357
- this._onErrors({ testId: this.testId, errors });
358
- }
359
- _errorLocation() {
360
- if (this.error?.stack)
361
- return (0, import_util.filteredStackTrace)(this.error.stack.split("\n"))[0];
362
- }
363
- async _testEndLocation() {
364
- try {
365
- const source = await import_fs.default.promises.readFile(this.file, "utf-8");
366
- return (0, import_babelHighlightUtils.findTestEndLocation)(source, { file: this.file, line: this.line, column: this.column });
367
- } catch {
368
- }
369
- }
370
346
  // ------------ TestInfo methods ------------
371
347
  async attach(name, options = {}) {
372
348
  const step = this._addStep({
@@ -99,7 +99,6 @@ class WorkerMain extends import_process.ProcessRunner {
99
99
  }, () => {
100
100
  }, () => {
101
101
  }, () => {
102
- }, () => {
103
102
  });
104
103
  const runnable = { type: "teardown" };
105
104
  await fakeTestInfo._runWithTimeout(runnable, () => this._loadIfNeeded()).catch(() => {
@@ -244,7 +243,6 @@ class WorkerMain extends import_process.ProcessRunner {
244
243
  (stepBeginPayload) => this.dispatchEvent("stepBegin", stepBeginPayload),
245
244
  (stepEndPayload) => this.dispatchEvent("stepEnd", stepEndPayload),
246
245
  (attachment) => this.dispatchEvent("attach", attachment),
247
- (errors) => this.dispatchEvent("testErrors", errors),
248
246
  (testPausedPayload) => this.dispatchEvent("testPaused", testPausedPayload)
249
247
  );
250
248
  const processAnnotation = (annotation) => {
@@ -285,7 +283,6 @@ class WorkerMain extends import_process.ProcessRunner {
285
283
  });
286
284
  if (isSkipped && nextTest && !hasAfterAllToRunBeforeNextTest) {
287
285
  testInfo.status = "skipped";
288
- testInfo._emitErrors();
289
286
  this.dispatchEvent("testEnd", buildTestEndPayload(testInfo));
290
287
  return;
291
288
  }
@@ -399,7 +396,6 @@ class WorkerMain extends import_process.ProcessRunner {
399
396
  testInfo.duration = testInfo._timeoutManager.defaultSlot().elapsed + afterHooksSlot.elapsed | 0;
400
397
  this._currentTest = null;
401
398
  (0, import_globals.setCurrentTestInfo)(null);
402
- testInfo._emitErrors();
403
399
  this.dispatchEvent("testEnd", buildTestEndPayload(testInfo));
404
400
  const preserveOutput = this._config.config.preserveOutput === "always" || this._config.config.preserveOutput === "failures-only" && testInfo._isFailure();
405
401
  if (!preserveOutput)
@@ -502,6 +498,7 @@ function buildTestEndPayload(testInfo) {
502
498
  testId: testInfo.testId,
503
499
  duration: testInfo.duration,
504
500
  status: testInfo.status,
501
+ errors: testInfo.errors,
505
502
  hasNonRetriableError: testInfo._hasNonRetriableError,
506
503
  expectedStatus: testInfo.expectedStatus,
507
504
  annotations: testInfo.annotations,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright",
3
- "version": "1.58.0-alpha-2025-12-04",
3
+ "version": "1.58.0-alpha-2025-12-06",
4
4
  "description": "A high-level API to automate web browsers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -64,7 +64,7 @@
64
64
  },
65
65
  "license": "Apache-2.0",
66
66
  "dependencies": {
67
- "playwright-core": "1.58.0-alpha-2025-12-04"
67
+ "playwright-core": "1.58.0-alpha-2025-12-06"
68
68
  },
69
69
  "optionalDependencies": {
70
70
  "fsevents": "2.3.2"
@@ -1,63 +0,0 @@
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 babelHighlightUtils_exports = {};
30
- __export(babelHighlightUtils_exports, {
31
- findTestEndLocation: () => findTestEndLocation
32
- });
33
- module.exports = __toCommonJS(babelHighlightUtils_exports);
34
- var import_path = __toESM(require("path"));
35
- var import_babelBundle = require("./babelBundle");
36
- function containsLocation(range, location) {
37
- if (location.line < range.start.line || location.line > range.end.line)
38
- return false;
39
- if (location.line === range.start.line && location.column < range.start.column)
40
- return false;
41
- if (location.line === range.end.line && location.column > range.end.column)
42
- return false;
43
- return true;
44
- }
45
- function findTestEndLocation(text, testStartLocation) {
46
- const ast = (0, import_babelBundle.babelParse)(text, import_path.default.basename(testStartLocation.file), false);
47
- let result;
48
- (0, import_babelBundle.traverse)(ast, {
49
- enter(path2) {
50
- if (import_babelBundle.types.isCallExpression(path2.node) && path2.node.loc && containsLocation(path2.node.loc, testStartLocation)) {
51
- const callNode = path2.node;
52
- const funcNode = callNode.arguments[callNode.arguments.length - 1];
53
- if (callNode.arguments.length >= 2 && import_babelBundle.types.isFunction(funcNode) && funcNode.body.loc)
54
- result = { file: testStartLocation.file, ...funcNode.body.loc.end };
55
- }
56
- }
57
- });
58
- return result;
59
- }
60
- // Annotate the CommonJS export names for ESM import in node:
61
- 0 && (module.exports = {
62
- findTestEndLocation
63
- });