playwright 1.58.0-alpha-2025-12-17 → 1.58.0-alpha-2025-12-18

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.
@@ -87,14 +87,15 @@ class FullConfigInternal {
87
87
  maxFailures: takeFirst(configCLIOverrides.debug ? 1 : void 0, configCLIOverrides.maxFailures, userConfig.maxFailures, 0),
88
88
  metadata: metadata ?? userConfig.metadata,
89
89
  preserveOutput: takeFirst(userConfig.preserveOutput, "always"),
90
+ projects: [],
91
+ quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
90
92
  reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]),
91
93
  reportSlowTests: takeFirst(userConfig.reportSlowTests, {
92
94
  max: 5,
93
95
  threshold: 3e5
94
96
  /* 5 minutes */
95
97
  }),
96
- quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
97
- projects: [],
98
+ runAgents: takeFirst(configCLIOverrides.runAgents, userConfig.runAgents, false),
98
99
  shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null),
99
100
  tags: globalTags,
100
101
  updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, "missing"),
package/lib/index.js CHANGED
@@ -111,7 +111,6 @@ const playwrightFixtures = {
111
111
  await browser.close({ reason: "Test ended." });
112
112
  }, { scope: "worker", timeout: 0 }],
113
113
  acceptDownloads: [({ contextOptions }, use) => use(contextOptions.acceptDownloads ?? true), { option: true, box: true }],
114
- agent: [({ contextOptions }, use) => use(contextOptions.agent), { option: true, box: true }],
115
114
  bypassCSP: [({ contextOptions }, use) => use(contextOptions.bypassCSP ?? false), { option: true, box: true }],
116
115
  colorScheme: [({ contextOptions }, use) => use(contextOptions.colorScheme === void 0 ? "light" : contextOptions.colorScheme), { option: true, box: true }],
117
116
  deviceScaleFactor: [({ contextOptions }, use) => use(contextOptions.deviceScaleFactor), { option: true, box: true }],
@@ -139,9 +138,9 @@ const playwrightFixtures = {
139
138
  }, { option: true, box: true }],
140
139
  serviceWorkers: [({ contextOptions }, use) => use(contextOptions.serviceWorkers ?? "allow"), { option: true, box: true }],
141
140
  contextOptions: [{}, { option: true, box: true }],
141
+ agent: [({}, use) => use(void 0), { option: true, box: true }],
142
142
  _combinedContextOptions: [async ({
143
143
  acceptDownloads,
144
- agent,
145
144
  bypassCSP,
146
145
  clientCertificates,
147
146
  colorScheme,
@@ -168,8 +167,6 @@ const playwrightFixtures = {
168
167
  const options = {};
169
168
  if (acceptDownloads !== void 0)
170
169
  options.acceptDownloads = acceptDownloads;
171
- if (agent !== void 0)
172
- options.agent = agent;
173
170
  if (bypassCSP !== void 0)
174
171
  options.bypassCSP = bypassCSP;
175
172
  if (colorScheme !== void 0)
@@ -612,14 +609,16 @@ class ArtifactsRecorder {
612
609
  }
613
610
  }
614
611
  async _cloneAgentCache(options) {
615
- if (!this._agent || this._agent.cacheMode === "ignore")
612
+ if (!this._agent)
616
613
  return;
617
- if (!this._agent.cacheFile && !this._agent.cachePathTemplate)
618
- return;
619
- const cacheFile = this._agent.cacheFile ?? this._testInfo._applyPathTemplate(this._agent.cachePathTemplate, "cache", ".json");
614
+ const cachePathTemplate = this._agent.cachePathTemplate ?? "{testDir}/{testFilePath}-cache.json";
615
+ const cacheFile = this._testInfo._applyPathTemplate(cachePathTemplate, "", ".json");
620
616
  const workerFile = await this._testInfo._cloneStorage(cacheFile);
621
- if (this._agent && workerFile)
622
- options.agent = { ...this._agent, cacheFile: workerFile };
617
+ options.agent = {
618
+ ...this._agent,
619
+ cacheFile: workerFile,
620
+ cacheMode: this._testInfo.config.runAgents ? "update" : "force"
621
+ };
623
622
  }
624
623
  async _upstreamAgentCache(context) {
625
624
  const agent = context._options.agent;
@@ -460,6 +460,7 @@ const baseFullConfig = {
460
460
  tags: [],
461
461
  updateSnapshots: "missing",
462
462
  updateSourceMethod: "patch",
463
+ runAgents: false,
463
464
  version: "",
464
465
  workers: 0,
465
466
  webServer: null
package/lib/program.js CHANGED
@@ -287,6 +287,7 @@ function overridesFromOptions(options) {
287
287
  ignoreSnapshots: options.ignoreSnapshots ? !!options.ignoreSnapshots : void 0,
288
288
  updateSnapshots: options.updateSnapshots,
289
289
  updateSourceMethod: options.updateSourceMethod,
290
+ runAgents: options.runAgents,
290
291
  workers: options.workers
291
292
  };
292
293
  if (options.browser) {
@@ -374,6 +375,7 @@ const testOptions = [
374
375
  ["--repeat-each <N>", { description: `Run each test N times (default: 1)` }],
375
376
  ["--reporter <reporter>", { description: `Reporter to use, comma-separated, can be ${import_config.builtInReporters.map((name) => `"${name}"`).join(", ")} (default: "${import_config.defaultReporter}")` }],
376
377
  ["--retries <retries>", { description: `Maximum retry count for flaky tests, zero for no retries (default: no retries)` }],
378
+ ["--run-agents", { description: `Run agents to generate the code for page.perform` }],
377
379
  ["--shard <shard>", { description: `Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5"` }],
378
380
  ["--test-list <file>", { description: `Path to a file containing a list of tests to run. See https://playwright.dev/docs/test-cli for more details.` }],
379
381
  ["--test-list-invert <file>", { description: `Path to a file containing a list of tests to skip. See https://playwright.dev/docs/test-cli for more details.` }],
@@ -258,6 +258,7 @@ class TestRunner extends import_events.default {
258
258
  },
259
259
  ...params.updateSnapshots ? { updateSnapshots: params.updateSnapshots } : {},
260
260
  ...params.updateSourceMethod ? { updateSourceMethod: params.updateSourceMethod } : {},
261
+ ...params.runAgents ? { runAgents: params.runAgents } : {},
261
262
  ...params.workers ? { workers: params.workers } : {}
262
263
  };
263
264
  const config = await this._loadConfigOrReportError(new import_internalReporter.InternalReporter([userReporter]), overrides);
@@ -31,7 +31,8 @@ __export(testInfo_exports, {
31
31
  StepSkipError: () => StepSkipError,
32
32
  TestInfoImpl: () => TestInfoImpl,
33
33
  TestSkipError: () => TestSkipError,
34
- TestStepInfoImpl: () => TestStepInfoImpl
34
+ TestStepInfoImpl: () => TestStepInfoImpl,
35
+ emtpyTestInfoCallbacks: () => emtpyTestInfoCallbacks
35
36
  });
36
37
  module.exports = __toCommonJS(testInfo_exports);
37
38
  var import_fs = __toESM(require("fs"));
@@ -43,6 +44,17 @@ var import_testTracing = require("./testTracing");
43
44
  var import_util2 = require("./util");
44
45
  var import_transform = require("../transform/transform");
45
46
  var import_babelHighlightUtils = require("../transform/babelHighlightUtils");
47
+ const emtpyTestInfoCallbacks = {
48
+ onStepBegin: () => {
49
+ },
50
+ onStepEnd: () => {
51
+ },
52
+ onAttach: () => {
53
+ },
54
+ onTestPaused: () => Promise.reject(new Error("TestInfoImpl not initialized")),
55
+ onCloneStorage: () => Promise.reject(new Error("TestInfoImpl not initialized")),
56
+ onUpstreamStorage: () => Promise.resolve()
57
+ };
46
58
  class TestInfoImpl {
47
59
  constructor(configInternal, projectInternal, workerParams, test, retry, callbacks) {
48
60
  this._snapshotNames = { lastAnonymousSnapshotIndex: 0, lastNamedSnapshotIndex: {} };
@@ -238,7 +250,7 @@ ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
238
250
  suggestedRebaseline: result.suggestedRebaseline,
239
251
  annotations: step.info.annotations
240
252
  };
241
- this._callbacks.onStepEnd?.(payload);
253
+ this._callbacks.onStepEnd(payload);
242
254
  }
243
255
  if (step.group !== "internal") {
244
256
  const errorForTrace = step.error ? { name: "", message: step.error.message || "", stack: step.error.stack } : void 0;
@@ -260,7 +272,7 @@ ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
260
272
  wallTime: Date.now(),
261
273
  location: step.location
262
274
  };
263
- this._callbacks.onStepBegin?.(payload);
275
+ this._callbacks.onStepBegin(payload);
264
276
  }
265
277
  if (step.group !== "internal") {
266
278
  this._tracing.appendBeforeActionForStep({
@@ -387,7 +399,7 @@ ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
387
399
  this._tracing.appendBeforeActionForStep({ stepId: stepId2, title: `Attach ${(0, import_utils.escapeWithQuotes)(attachment.name, '"')}`, category: "test.attach", stack: [] });
388
400
  this._tracing.appendAfterActionForStep(stepId2, void 0, [attachment]);
389
401
  }
390
- this._callbacks.onAttach?.({
402
+ this._callbacks.onAttach({
391
403
  testId: this.testId,
392
404
  name: attachment.name,
393
405
  contentType: attachment.contentType,
@@ -483,7 +495,7 @@ ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
483
495
  }
484
496
  async _cloneStorage(cacheFileTemplate) {
485
497
  const storageFile = this._applyPathTemplate(cacheFileTemplate, "cache", ".json");
486
- return await this._callbacks.onCloneStorage?.({ storageFile });
498
+ return await this._callbacks.onCloneStorage({ storageFile });
487
499
  }
488
500
  async _upstreamStorage(workerFile) {
489
501
  await this._callbacks.onUpstreamStorage?.({ workerFile });
@@ -538,5 +550,6 @@ const stepSymbol = Symbol("step");
538
550
  StepSkipError,
539
551
  TestInfoImpl,
540
552
  TestSkipError,
541
- TestStepInfoImpl
553
+ TestStepInfoImpl,
554
+ emtpyTestInfoCallbacks
542
555
  });
@@ -95,7 +95,7 @@ class WorkerMain extends import_process.ProcessRunner {
95
95
  if (!this._config) {
96
96
  return;
97
97
  }
98
- const fakeTestInfo = new import_testInfo.TestInfoImpl(this._config, this._project, this._params, void 0, 0, {});
98
+ const fakeTestInfo = new import_testInfo.TestInfoImpl(this._config, this._project, this._params, void 0, 0, import_testInfo.emtpyTestInfoCallbacks);
99
99
  const runnable = { type: "teardown" };
100
100
  await fakeTestInfo._runWithTimeout(runnable, () => this._loadIfNeeded()).catch(() => {
101
101
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright",
3
- "version": "1.58.0-alpha-2025-12-17",
3
+ "version": "1.58.0-alpha-2025-12-18",
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-17"
67
+ "playwright-core": "1.58.0-alpha-2025-12-18"
68
68
  },
69
69
  "optionalDependencies": {
70
70
  "fsevents": "2.3.2"
package/types/test.d.ts CHANGED
@@ -1611,6 +1611,12 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
1611
1611
  */
1612
1612
  retries?: number;
1613
1613
 
1614
+ /**
1615
+ * Run agents to generate the code for
1616
+ * [page.perform(task[, options])](https://playwright.dev/docs/api/class-page#page-perform) and similar.
1617
+ */
1618
+ runAgents?: boolean;
1619
+
1614
1620
  /**
1615
1621
  * Shard tests and execute only the selected shard. Specify in the one-based form like `{ total: 5, current: 2 }`.
1616
1622
  *
@@ -2067,6 +2073,12 @@ export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
2067
2073
  */
2068
2074
  rootDir: string;
2069
2075
 
2076
+ /**
2077
+ * Run agents to generate the code for
2078
+ * [page.perform(task[, options])](https://playwright.dev/docs/api/class-page#page-perform) and similar.
2079
+ */
2080
+ runAgents: boolean;
2081
+
2070
2082
  /**
2071
2083
  * See [testConfig.shard](https://playwright.dev/docs/api/class-testconfig#test-config-shard).
2072
2084
  */
@@ -6644,7 +6656,6 @@ export type Fixtures<T extends {} = {}, W extends {} = {}, PT extends {} = {}, P
6644
6656
  [K in Exclude<keyof T, keyof PW | keyof PT>]?: TestFixtureValue<T[K], T & W & PT & PW> | [TestFixtureValue<T[K], T & W & PT & PW>, { scope?: 'test', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean | 'self' }];
6645
6657
  };
6646
6658
 
6647
- type Agent = Exclude<BrowserContextOptions['agent'], undefined> & { cachePathTemplate?: string } | undefined;
6648
6659
  type BrowserName = 'chromium' | 'firefox' | 'webkit';
6649
6660
  type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>;
6650
6661
  type ColorScheme = Exclude<BrowserContextOptions['colorScheme'], undefined>;
@@ -6935,6 +6946,15 @@ export interface PlaywrightWorkerOptions {
6935
6946
  export type ScreenshotMode = 'off' | 'on' | 'only-on-failure' | 'on-first-failure';
6936
6947
  export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' | 'retain-on-first-failure';
6937
6948
  export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
6949
+ export type Agent = {
6950
+ provider: string;
6951
+ model: string;
6952
+ cachePathTemplate?: string;
6953
+ maxTurns?: number;
6954
+ maxTokens?: number;
6955
+ runAgents?: boolean;
6956
+ secrets?: { [key: string]: string };
6957
+ };
6938
6958
 
6939
6959
  /**
6940
6960
  * Playwright Test provides many options to configure test environment,
@@ -6975,11 +6995,7 @@ export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
6975
6995
  *
6976
6996
  */
6977
6997
  export interface PlaywrightTestOptions {
6978
- /**
6979
- * Agent settings for [page.perform(task[, options])](https://playwright.dev/docs/api/class-page#page-perform) and
6980
- * [page.extract(query, schema[, options])](https://playwright.dev/docs/api/class-page#page-extract).
6981
- */
6982
- agent: Agent;
6998
+ agent: Agent | undefined;
6983
6999
  /**
6984
7000
  * Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted.
6985
7001
  *