patchright-core 1.56.1 → 1.58.2

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.
Files changed (180) hide show
  1. package/ThirdPartyNotices.txt +3134 -560
  2. package/bin/install_webkit_wsl.ps1 +1 -3
  3. package/browsers.json +21 -22
  4. package/lib/cli/program.js +16 -60
  5. package/lib/client/api.js +3 -3
  6. package/lib/client/browser.js +3 -5
  7. package/lib/client/browserContext.js +62 -8
  8. package/lib/client/browserType.js +4 -3
  9. package/lib/client/connection.js +4 -0
  10. package/lib/client/consoleMessage.js +5 -1
  11. package/lib/client/electron.js +1 -1
  12. package/lib/client/elementHandle.js +3 -0
  13. package/lib/client/events.js +5 -1
  14. package/lib/client/fetch.js +3 -4
  15. package/lib/client/frame.js +10 -1
  16. package/lib/client/locator.js +12 -1
  17. package/lib/client/network.js +5 -1
  18. package/lib/client/page.js +31 -6
  19. package/lib/client/pageAgent.js +64 -0
  20. package/lib/client/platform.js +3 -0
  21. package/lib/client/playwright.js +1 -5
  22. package/lib/client/tracing.js +7 -5
  23. package/lib/client/worker.js +22 -0
  24. package/lib/generated/clockSource.js +1 -1
  25. package/lib/generated/injectedScriptSource.js +1 -1
  26. package/lib/generated/pollingRecorderSource.js +1 -1
  27. package/lib/inProcessFactory.js +0 -2
  28. package/lib/mcpBundle.js +84 -0
  29. package/lib/mcpBundleImpl/index.js +147 -0
  30. package/lib/protocol/serializers.js +5 -0
  31. package/lib/protocol/validator.js +112 -50
  32. package/lib/remote/playwrightServer.js +1 -2
  33. package/lib/server/agent/actionRunner.js +335 -0
  34. package/lib/server/agent/actions.js +128 -0
  35. package/lib/server/agent/codegen.js +111 -0
  36. package/lib/server/agent/context.js +150 -0
  37. package/lib/server/agent/expectTools.js +156 -0
  38. package/lib/server/agent/pageAgent.js +204 -0
  39. package/lib/server/agent/performTools.js +262 -0
  40. package/lib/server/agent/tool.js +109 -0
  41. package/lib/server/android/android.js +1 -1
  42. package/lib/server/artifact.js +1 -1
  43. package/lib/server/bidi/bidiBrowser.js +81 -22
  44. package/lib/server/bidi/bidiChromium.js +9 -13
  45. package/lib/server/bidi/bidiConnection.js +1 -0
  46. package/lib/server/bidi/bidiDeserializer.js +116 -0
  47. package/lib/server/bidi/bidiExecutionContext.js +75 -29
  48. package/lib/server/bidi/bidiFirefox.js +7 -9
  49. package/lib/server/bidi/bidiNetworkManager.js +1 -1
  50. package/lib/server/bidi/bidiPage.js +61 -30
  51. package/lib/server/bidi/third_party/bidiProtocolCore.js +1 -0
  52. package/lib/server/browserContext.js +43 -36
  53. package/lib/server/browserType.js +12 -4
  54. package/lib/server/chromium/chromium.js +26 -21
  55. package/lib/server/chromium/chromiumSwitches.js +12 -3
  56. package/lib/server/chromium/crBrowser.js +30 -12
  57. package/lib/server/chromium/crConnection.js +0 -5
  58. package/lib/server/chromium/crCoverage.js +13 -1
  59. package/lib/server/chromium/crDevTools.js +0 -2
  60. package/lib/server/chromium/crNetworkManager.js +107 -18
  61. package/lib/server/chromium/crPage.js +68 -124
  62. package/lib/server/chromium/crServiceWorker.js +14 -1
  63. package/lib/server/codegen/javascript.js +6 -29
  64. package/lib/server/console.js +5 -1
  65. package/lib/server/deviceDescriptorsSource.json +56 -56
  66. package/lib/server/dispatchers/browserContextDispatcher.js +26 -8
  67. package/lib/server/dispatchers/dispatcher.js +6 -13
  68. package/lib/server/dispatchers/frameDispatcher.js +1 -1
  69. package/lib/server/dispatchers/jsHandleDispatcher.js +2 -2
  70. package/lib/server/dispatchers/pageAgentDispatcher.js +96 -0
  71. package/lib/server/dispatchers/pageDispatcher.js +14 -22
  72. package/lib/server/dispatchers/playwrightDispatcher.js +0 -4
  73. package/lib/server/dom.js +12 -3
  74. package/lib/server/electron/electron.js +6 -3
  75. package/lib/server/firefox/ffBrowser.js +10 -20
  76. package/lib/server/firefox/ffConnection.js +0 -5
  77. package/lib/server/firefox/ffNetworkManager.js +2 -2
  78. package/lib/server/firefox/ffPage.js +18 -24
  79. package/lib/server/firefox/firefox.js +18 -9
  80. package/lib/server/frameSelectors.js +18 -8
  81. package/lib/server/frames.js +257 -87
  82. package/lib/server/input.js +7 -3
  83. package/lib/server/instrumentation.js +3 -0
  84. package/lib/server/javascript.js +8 -4
  85. package/lib/server/launchApp.js +2 -1
  86. package/lib/server/localUtils.js +4 -8
  87. package/lib/server/network.js +50 -12
  88. package/lib/server/page.js +112 -126
  89. package/lib/server/playwright.js +2 -4
  90. package/lib/server/progress.js +26 -6
  91. package/lib/server/recorder/recorderApp.js +80 -101
  92. package/lib/server/recorder.js +3 -2
  93. package/lib/server/registry/browserFetcher.js +6 -4
  94. package/lib/server/registry/index.js +278 -189
  95. package/lib/server/registry/oopDownloadBrowserMain.js +9 -2
  96. package/lib/server/screencast.js +190 -0
  97. package/lib/server/screenshotter.js +6 -0
  98. package/lib/server/socksClientCertificatesInterceptor.js +1 -1
  99. package/lib/server/trace/recorder/snapshotter.js +17 -8
  100. package/lib/server/trace/recorder/snapshotterInjected.js +30 -72
  101. package/lib/server/trace/recorder/tracing.js +31 -21
  102. package/lib/server/trace/viewer/traceParser.js +72 -0
  103. package/lib/server/trace/viewer/traceViewer.js +45 -40
  104. package/lib/server/utils/comparators.js +3 -25
  105. package/lib/server/utils/expectUtils.js +87 -2
  106. package/lib/server/utils/hostPlatform.js +30 -3
  107. package/lib/server/utils/httpServer.js +5 -20
  108. package/lib/server/utils/imageUtils.js +141 -0
  109. package/lib/server/utils/network.js +55 -40
  110. package/lib/server/utils/nodePlatform.js +6 -0
  111. package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +35 -24
  112. package/lib/server/webkit/webkit.js +5 -16
  113. package/lib/server/webkit/wkBrowser.js +2 -6
  114. package/lib/server/webkit/wkConnection.js +1 -6
  115. package/lib/server/webkit/wkInterceptableRequest.js +29 -1
  116. package/lib/server/webkit/wkPage.js +76 -51
  117. package/lib/server/webkit/wkWorkers.js +2 -1
  118. package/lib/utils/isomorphic/ariaSnapshot.js +63 -0
  119. package/lib/utils/isomorphic/locatorGenerators.js +24 -8
  120. package/lib/utils/isomorphic/lruCache.js +51 -0
  121. package/lib/utils/isomorphic/mimeType.js +1 -1
  122. package/lib/utils/isomorphic/protocolFormatter.js +3 -0
  123. package/lib/utils/isomorphic/protocolMetainfo.js +11 -2
  124. package/lib/utils/isomorphic/stringUtils.js +49 -0
  125. package/lib/utils/isomorphic/trace/entries.js +16 -0
  126. package/lib/utils/isomorphic/trace/snapshotRenderer.js +499 -0
  127. package/lib/utils/isomorphic/trace/snapshotServer.js +120 -0
  128. package/lib/utils/isomorphic/trace/snapshotStorage.js +89 -0
  129. package/lib/utils/isomorphic/trace/traceLoader.js +131 -0
  130. package/lib/utils/isomorphic/trace/traceModel.js +365 -0
  131. package/lib/utils/isomorphic/trace/traceModernizer.js +400 -0
  132. package/lib/utils/isomorphic/trace/versions/traceV3.js +16 -0
  133. package/lib/utils/isomorphic/trace/versions/traceV4.js +16 -0
  134. package/lib/utils/isomorphic/trace/versions/traceV5.js +16 -0
  135. package/lib/utils/isomorphic/trace/versions/traceV6.js +16 -0
  136. package/lib/utils/isomorphic/trace/versions/traceV7.js +16 -0
  137. package/lib/utils/isomorphic/trace/versions/traceV8.js +16 -0
  138. package/lib/utils/isomorphic/urlMatch.js +19 -5
  139. package/lib/utils/isomorphic/yaml.js +84 -0
  140. package/lib/utils.js +4 -0
  141. package/lib/utilsBundle.js +1 -1
  142. package/lib/utilsBundleImpl/index.js +124 -124
  143. package/lib/vite/htmlReport/index.html +21 -21
  144. package/lib/vite/recorder/assets/codeMirrorModule-CFUTFUO7.js +32 -0
  145. package/lib/vite/recorder/assets/{codeMirrorModule-C3UTv-Ge.css → codeMirrorModule-DYBRYzYX.css} +1 -1
  146. package/lib/vite/recorder/assets/{index-Ri0uHF7I.css → index-BSjZa4pk.css} +1 -1
  147. package/lib/vite/recorder/assets/index-CVkBxsGf.js +193 -0
  148. package/lib/vite/recorder/index.html +2 -2
  149. package/lib/vite/traceViewer/assets/codeMirrorModule-BVA4h_ZY.js +32 -0
  150. package/lib/vite/traceViewer/assets/defaultSettingsView-CjfmcdOz.js +266 -0
  151. package/lib/vite/traceViewer/{codeMirrorModule.C3UTv-Ge.css → codeMirrorModule.DYBRYzYX.css} +1 -1
  152. package/lib/vite/traceViewer/defaultSettingsView.7ch9cixO.css +1 -0
  153. package/lib/vite/traceViewer/index.BVu7tZDe.css +1 -0
  154. package/lib/vite/traceViewer/index.BtyWtaE-.js +2 -0
  155. package/lib/vite/traceViewer/index.html +6 -6
  156. package/lib/vite/traceViewer/manifest.webmanifest +16 -0
  157. package/lib/vite/traceViewer/snapshot.html +3 -3
  158. package/lib/vite/traceViewer/sw.bundle.js +5 -3
  159. package/lib/vite/traceViewer/uiMode.fyrXARf2.js +5 -0
  160. package/lib/vite/traceViewer/uiMode.html +3 -3
  161. package/package.json +2 -1
  162. package/types/protocol.d.ts +939 -245
  163. package/types/types.d.ts +143 -153
  164. package/lib/client/accessibility.js +0 -49
  165. package/lib/server/accessibility.js +0 -69
  166. package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
  167. package/lib/server/chromium/crAccessibility.js +0 -263
  168. package/lib/server/firefox/ffAccessibility.js +0 -238
  169. package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
  170. package/lib/server/webkit/wkAccessibility.js +0 -237
  171. package/lib/server/webkit/wsl/webkit-wsl-transport-client.js +0 -74
  172. package/lib/server/webkit/wsl/webkit-wsl-transport-server.js +0 -113
  173. package/lib/vite/recorder/assets/codeMirrorModule-RJCXzfmE.js +0 -24
  174. package/lib/vite/recorder/assets/index-Y-X2TGJv.js +0 -193
  175. package/lib/vite/traceViewer/assets/codeMirrorModule-rbQPefq7.js +0 -24
  176. package/lib/vite/traceViewer/assets/defaultSettingsView-CLbol9XR.js +0 -265
  177. package/lib/vite/traceViewer/defaultSettingsView.TQ8_7ybu.css +0 -1
  178. package/lib/vite/traceViewer/index.I8N9v4jT.css +0 -1
  179. package/lib/vite/traceViewer/index.zIVi6mN9.js +0 -2
  180. package/lib/vite/traceViewer/uiMode.B_CpmIpF.js +0 -5
@@ -39,11 +39,11 @@ class JSHandleDispatcher extends import_dispatcher.Dispatcher {
39
39
  return scope.connection.existingDispatcher(handle) || new JSHandleDispatcher(scope, handle);
40
40
  }
41
41
  async evaluateExpression(params, progress) {
42
- const jsHandle = await progress.race(this._object.evaluateExpression(params.expression, { isFunction: params.isFunction }, parseArgument(params.arg)));
42
+ const jsHandle = await progress.race(this._object.evaluateExpression(params.expression, { isFunction: params.isFunction }, parseArgument(params.arg), params.isolatedContext));
43
43
  return { value: serializeResult(jsHandle) };
44
44
  }
45
45
  async evaluateExpressionHandle(params, progress) {
46
- const jsHandle = await progress.race(this._object.evaluateExpressionHandle(params.expression, { isFunction: params.isFunction }, parseArgument(params.arg)));
46
+ const jsHandle = await progress.race(this._object.evaluateExpressionHandle(params.expression, { isFunction: params.isFunction }, parseArgument(params.arg), params.isolatedContext));
47
47
  return { handle: import_elementHandlerDispatcher.ElementHandleDispatcher.fromJSOrElementHandle(this.parentScope(), jsHandle) };
48
48
  }
49
49
  async getProperty(params, progress) {
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var pageAgentDispatcher_exports = {};
20
+ __export(pageAgentDispatcher_exports, {
21
+ PageAgentDispatcher: () => PageAgentDispatcher
22
+ });
23
+ module.exports = __toCommonJS(pageAgentDispatcher_exports);
24
+ var import_dispatcher = require("./dispatcher");
25
+ var import_pageAgent = require("../agent/pageAgent");
26
+ var import_instrumentation = require("../instrumentation");
27
+ var import_context = require("../agent/context");
28
+ class PageAgentDispatcher extends import_dispatcher.Dispatcher {
29
+ constructor(scope, options) {
30
+ super(scope, new import_instrumentation.SdkObject(scope._object, "pageAgent"), "PageAgent", { page: scope });
31
+ this._type_PageAgent = true;
32
+ this._type_EventTarget = true;
33
+ this._usage = { turns: 0, inputTokens: 0, outputTokens: 0 };
34
+ this._page = scope._object;
35
+ this._context = new import_context.Context(this._page, options, this._eventSupport());
36
+ }
37
+ async perform(params, progress) {
38
+ try {
39
+ await (0, import_pageAgent.pageAgentPerform)(progress, this._context, params.task, params);
40
+ } finally {
41
+ this._context.pushHistory({ type: "perform", description: params.task });
42
+ }
43
+ return { usage: this._usage };
44
+ }
45
+ async expect(params, progress) {
46
+ try {
47
+ await (0, import_pageAgent.pageAgentExpect)(progress, this._context, params.expectation, params);
48
+ } finally {
49
+ this._context.pushHistory({ type: "expect", description: params.expectation });
50
+ }
51
+ return { usage: this._usage };
52
+ }
53
+ async extract(params, progress) {
54
+ const result = await (0, import_pageAgent.pageAgentExtract)(progress, this._context, params.query, params.schema, params);
55
+ return { result, usage: this._usage };
56
+ }
57
+ async usage(params, progress) {
58
+ return { usage: this._usage };
59
+ }
60
+ async dispose(params, progress) {
61
+ progress.metadata.potentiallyClosesScope = true;
62
+ void this.stopPendingOperations(new Error("The agent is disposed"));
63
+ this._dispose();
64
+ }
65
+ _eventSupport() {
66
+ const self = this;
67
+ return {
68
+ onBeforeTurn(params) {
69
+ const userMessage = params.conversation.messages.find((m) => m.role === "user");
70
+ self._dispatchEvent("turn", { role: "user", message: userMessage?.content ?? "" });
71
+ },
72
+ onAfterTurn(params) {
73
+ const usage = { inputTokens: params.totalUsage.input, outputTokens: params.totalUsage.output };
74
+ const intent = params.assistantMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
75
+ self._dispatchEvent("turn", { role: "assistant", message: intent, usage });
76
+ if (!params.assistantMessage.content.filter((c) => c.type === "tool_call").length)
77
+ self._dispatchEvent("turn", { role: "assistant", message: `no tool calls`, usage });
78
+ self._usage = { turns: self._usage.turns + 1, inputTokens: self._usage.inputTokens + usage.inputTokens, outputTokens: self._usage.outputTokens + usage.outputTokens };
79
+ },
80
+ onBeforeToolCall(params) {
81
+ self._dispatchEvent("turn", { role: "assistant", message: `call tool "${params.toolCall.name}"` });
82
+ },
83
+ onAfterToolCall(params) {
84
+ const suffix = params.toolCall.result?.isError ? "failed" : "succeeded";
85
+ self._dispatchEvent("turn", { role: "user", message: `tool "${params.toolCall.name}" ${suffix}` });
86
+ },
87
+ onToolCallError(params) {
88
+ self._dispatchEvent("turn", { role: "user", message: `tool "${params.toolCall.name}" failed: ${params.error.message}` });
89
+ }
90
+ };
91
+ }
92
+ }
93
+ // Annotate the CommonJS export names for ESM import in node:
94
+ 0 && (module.exports = {
95
+ PageAgentDispatcher
96
+ });
@@ -36,6 +36,7 @@ var import_networkDispatchers3 = require("./networkDispatchers");
36
36
  var import_webSocketRouteDispatcher = require("./webSocketRouteDispatcher");
37
37
  var import_instrumentation = require("../instrumentation");
38
38
  var import_urlMatch = require("../../utils/isomorphic/urlMatch");
39
+ var import_pageAgentDispatcher = require("./pageAgentDispatcher");
39
40
  class PageDispatcher extends import_dispatcher.Dispatcher {
40
41
  constructor(parentScope, page) {
41
42
  const mainFrame = import_frameDispatcher.FrameDispatcher.from(parentScope, page.mainFrame());
@@ -103,19 +104,6 @@ class PageDispatcher extends import_dispatcher.Dispatcher {
103
104
  page() {
104
105
  return this._page;
105
106
  }
106
- serializeConsoleMessage(message) {
107
- return {
108
- type: message.type(),
109
- text: message.text(),
110
- args: message.args().map((a) => {
111
- const elementHandle = a.asElement();
112
- if (elementHandle)
113
- return import_elementHandlerDispatcher.ElementHandleDispatcher.from(import_frameDispatcher.FrameDispatcher.from(this.parentScope(), elementHandle._frame), elementHandle);
114
- return import_jsHandleDispatcher.JSHandleDispatcher.fromJSHandle(this, a);
115
- }),
116
- location: message.location()
117
- };
118
- }
119
107
  async exposeBinding(params, progress) {
120
108
  const binding = await this._page.exposeBinding(progress, params.name, !!params.needsHandle, (source, ...args) => {
121
109
  if (this._disposed)
@@ -237,7 +225,7 @@ class PageDispatcher extends import_dispatcher.Dispatcher {
237
225
  }
238
226
  async consoleMessages(params, progress) {
239
227
  this._subscriptions.add("console");
240
- return { messages: this._page.consoleMessages().map((message) => this.serializeConsoleMessage(message)) };
228
+ return { messages: this._page.consoleMessages().map((message) => this.parentScope().serializeConsoleMessage(message, this)) };
241
229
  }
242
230
  async pageErrors(params, progress) {
243
231
  return { errors: this._page.pageErrors().map((error) => (0, import_errors.serializeError)(error)) };
@@ -265,13 +253,6 @@ class PageDispatcher extends import_dispatcher.Dispatcher {
265
253
  progress.metadata.point = { x: params.x, y: params.y };
266
254
  await this._page.touchscreen.tap(progress, params.x, params.y);
267
255
  }
268
- async accessibilitySnapshot(params, progress) {
269
- const rootAXNode = await progress.race(this._page.accessibility.snapshot({
270
- interestingOnly: params.interestingOnly,
271
- root: params.root ? params.root._elementHandle : void 0
272
- }));
273
- return { rootAXNode: rootAXNode || void 0 };
274
- }
275
256
  async pdf(params, progress) {
276
257
  if (!this._page.pdf)
277
258
  throw new Error("PDF generation is only supported for Headless Chromium");
@@ -283,7 +264,7 @@ class PageDispatcher extends import_dispatcher.Dispatcher {
283
264
  return { requests: this._page.networkRequests().map((request) => import_networkDispatchers.RequestDispatcher.from(this.parentScope(), request)) };
284
265
  }
285
266
  async snapshotForAI(params, progress) {
286
- return { snapshot: await this._page.snapshotForAI(progress) };
267
+ return await this._page.snapshotForAI(progress, params);
287
268
  }
288
269
  async bringToFront(params, progress) {
289
270
  await progress.race(this._page.bringToFront());
@@ -308,6 +289,9 @@ class PageDispatcher extends import_dispatcher.Dispatcher {
308
289
  const coverage = this._page.coverage;
309
290
  return await coverage.stopCSSCoverage();
310
291
  }
292
+ async agent(params, progress) {
293
+ return { agent: new import_pageAgentDispatcher.PageAgentDispatcher(this, params) };
294
+ }
311
295
  _onFrameAttached(frame) {
312
296
  this._dispatchEvent("frameAttached", { frame: import_frameDispatcher.FrameDispatcher.from(this.parentScope(), frame) });
313
297
  }
@@ -351,6 +335,8 @@ class WorkerDispatcher extends import_dispatcher.Dispatcher {
351
335
  url: worker.url
352
336
  });
353
337
  this._type_Worker = true;
338
+ this._type_EventTarget = true;
339
+ this._subscriptions = /* @__PURE__ */ new Set();
354
340
  this.addObjectListener(import_page.Worker.Events.Close, () => this._dispatchEvent("close"));
355
341
  }
356
342
  static fromNullable(scope, worker) {
@@ -365,6 +351,12 @@ class WorkerDispatcher extends import_dispatcher.Dispatcher {
365
351
  async evaluateExpressionHandle(params, progress) {
366
352
  return { handle: import_jsHandleDispatcher.JSHandleDispatcher.fromJSHandle(this, await progress.race(this._object.evaluateExpressionHandle(params.expression, params.isFunction, (0, import_jsHandleDispatcher.parseArgument)(params.arg)))) };
367
353
  }
354
+ async updateSubscription(params, progress) {
355
+ if (params.enabled)
356
+ this._subscriptions.add(params.event);
357
+ else
358
+ this._subscriptions.delete(params.event);
359
+ }
368
360
  }
369
361
  class BindingCallDispatcher extends import_dispatcher.Dispatcher {
370
362
  constructor(scope, name, needsHandle, source, args) {
@@ -39,15 +39,11 @@ class PlaywrightDispatcher extends import_dispatcher.Dispatcher {
39
39
  const chromium = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.chromium, denyLaunch);
40
40
  const firefox = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.firefox, denyLaunch);
41
41
  const webkit = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.webkit, denyLaunch);
42
- const _bidiChromium = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright._bidiChromium, denyLaunch);
43
- const _bidiFirefox = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright._bidiFirefox, denyLaunch);
44
42
  const android = new import_androidDispatcher.AndroidDispatcher(scope, playwright.android);
45
43
  const initializer = {
46
44
  chromium,
47
45
  firefox,
48
46
  webkit,
49
- _bidiChromium,
50
- _bidiFirefox,
51
47
  android,
52
48
  electron: new import_electronDispatcher.ElectronDispatcher(scope, playwright.electron, denyLaunch),
53
49
  utils: playwright.options.isServer ? void 0 : new import_localUtilsDispatcher.LocalUtilsDispatcher(scope, playwright),
package/lib/server/dom.js CHANGED
@@ -255,6 +255,7 @@ class ElementHandle extends js.JSHandle {
255
255
  async _retryAction(progress, actionName, action, options) {
256
256
  let retry = 0;
257
257
  const waitTime = [0, 20, 100, 100, 500];
258
+ const noAutoWaiting = options.__testHookNoAutoWaiting ?? options.noAutoWaiting;
258
259
  while (true) {
259
260
  if (retry) {
260
261
  progress.log(`retrying ${actionName} action${options.trial ? " (trial run)" : ""}`);
@@ -268,35 +269,43 @@ class ElementHandle extends js.JSHandle {
268
269
  } else {
269
270
  progress.log(`attempting ${actionName} action${options.trial ? " (trial run)" : ""}`);
270
271
  }
271
- if (!options.skipActionPreChecks && !options.force)
272
+ if (!options.skipActionPreChecks && !options.force && !noAutoWaiting)
272
273
  await this._frame._page.performActionPreChecks(progress);
273
274
  const result = await action(retry);
274
275
  ++retry;
275
276
  if (result === "error:notvisible") {
276
- if (options.force)
277
+ if (options.force || noAutoWaiting)
277
278
  throw new NonRecoverableDOMError("Element is not visible");
278
279
  progress.log(" element is not visible");
279
280
  continue;
280
281
  }
281
282
  if (result === "error:notinviewport") {
282
- if (options.force)
283
+ if (options.force || noAutoWaiting)
283
284
  throw new NonRecoverableDOMError("Element is outside of the viewport");
284
285
  progress.log(" element is outside of the viewport");
285
286
  continue;
286
287
  }
287
288
  if (result === "error:optionsnotfound") {
289
+ if (noAutoWaiting)
290
+ throw new NonRecoverableDOMError("Did not find some options");
288
291
  progress.log(" did not find some options");
289
292
  continue;
290
293
  }
291
294
  if (result === "error:optionnotenabled") {
295
+ if (noAutoWaiting)
296
+ throw new NonRecoverableDOMError("Option being selected is not enabled");
292
297
  progress.log(" option being selected is not enabled");
293
298
  continue;
294
299
  }
295
300
  if (typeof result === "object" && "hitTargetDescription" in result) {
301
+ if (noAutoWaiting)
302
+ throw new NonRecoverableDOMError(`${result.hitTargetDescription} intercepts pointer events`);
296
303
  progress.log(` ${result.hitTargetDescription} intercepts pointer events`);
297
304
  continue;
298
305
  }
299
306
  if (typeof result === "object" && "missingState" in result) {
307
+ if (noAutoWaiting)
308
+ throw new NonRecoverableDOMError(`Element is not ${result.missingState}`);
300
309
  progress.log(` element is not ${result.missingState}`);
301
310
  continue;
302
311
  }
@@ -97,7 +97,7 @@ class ElectronApplication extends import_instrumentation.SdkObject {
97
97
  if (!this._nodeExecutionContext)
98
98
  return;
99
99
  const args = event.args.map((arg) => (0, import_crExecutionContext.createHandle)(this._nodeExecutionContext, arg));
100
- const message = new import_console.ConsoleMessage(null, event.type, void 0, args, (0, import_crProtocolHelper.toConsoleMessageLocation)(event.stackTrace));
100
+ const message = new import_console.ConsoleMessage(null, null, event.type, void 0, args, (0, import_crProtocolHelper.toConsoleMessageLocation)(event.stackTrace));
101
101
  this.emit(ElectronApplication.Events.Console, message);
102
102
  }
103
103
  async initialize() {
@@ -158,8 +158,8 @@ class Electron extends import_instrumentation.SdkObject {
158
158
  let shell = false;
159
159
  if (process.platform === "win32") {
160
160
  shell = true;
161
- command = `"${command}"`;
162
- electronArguments = electronArguments.map((arg) => `"${arg}"`);
161
+ command = [command, ...electronArguments].map((arg) => `"${escapeDoubleQuotes(arg)}"`).join(" ");
162
+ electronArguments = [];
163
163
  }
164
164
  delete env.NODE_OPTIONS;
165
165
  const { launchedProcess, gracefullyClose, kill } = await (0, import_processLauncher.launchProcess)({
@@ -263,6 +263,9 @@ async function waitForLine(progress, process2, regex) {
263
263
  import_eventsHelper.eventsHelper.removeEventListeners(listeners);
264
264
  }
265
265
  }
266
+ function escapeDoubleQuotes(str) {
267
+ return str.replace(/"/g, '\\"');
268
+ }
266
269
  // Annotate the CommonJS export names for ESM import in node:
267
270
  0 && (module.exports = {
268
271
  Electron,
@@ -54,7 +54,6 @@ class FFBrowser extends import_browser.Browser {
54
54
  this.session.on("Browser.detachedFromTarget", this._onDetachedFromTarget.bind(this));
55
55
  this.session.on("Browser.downloadCreated", this._onDownloadCreated.bind(this));
56
56
  this.session.on("Browser.downloadFinished", this._onDownloadFinished.bind(this));
57
- this.session.on("Browser.videoRecordingFinished", this._onVideoRecordingFinished.bind(this));
58
57
  }
59
58
  static async connect(parent, transport, options) {
60
59
  const connection = new import_ffConnection.FFConnection(transport, options.protocolLogger, options.browserLogsCollector);
@@ -141,12 +140,9 @@ class FFBrowser extends import_browser.Browser {
141
140
  const error = payload.canceled ? "canceled" : payload.error;
142
141
  this._downloadFinished(payload.uuid, error);
143
142
  }
144
- _onVideoRecordingFinished(payload) {
145
- this._takeVideo(payload.screencastId)?.reportFinished();
146
- }
147
143
  _onDisconnect() {
148
144
  for (const video of this._idToVideo.values())
149
- video.artifact.reportFinished(new import_errors.TargetClosedError());
145
+ video.artifact.reportFinished(new import_errors.TargetClosedError(this.closeReason()));
150
146
  this._idToVideo.clear();
151
147
  for (const ffPage of this._ffPages.values())
152
148
  ffPage.didClose();
@@ -199,15 +195,13 @@ class FFBrowserContext extends import_browserContext.BrowserContext {
199
195
  promises.push(this.doUpdateOffline());
200
196
  promises.push(this.doUpdateDefaultEmulatedMedia());
201
197
  if (this._options.recordVideo) {
202
- promises.push(this._ensureVideosPath().then(() => {
203
- return this._browser.session.send("Browser.setVideoRecordingOptions", {
204
- // validateBrowserContextOptions ensures correct video size.
205
- options: {
206
- ...this._options.recordVideo.size,
207
- dir: this._options.recordVideo.dir
208
- },
209
- browserContextId: this._browserContextId
210
- });
198
+ promises.push(this._browser.session.send("Browser.setScreencastOptions", {
199
+ // validateBrowserContextOptions ensures correct video size.
200
+ options: {
201
+ ...this._options.recordVideo.size,
202
+ quality: 90
203
+ },
204
+ browserContextId: this._browserContextId
211
205
  }));
212
206
  }
213
207
  const proxy = this._options.proxyOverride || this._options.proxy;
@@ -379,12 +373,8 @@ class FFBrowserContext extends import_browserContext.BrowserContext {
379
373
  }
380
374
  async doClose(reason) {
381
375
  if (!this._browserContextId) {
382
- if (this._options.recordVideo) {
383
- await this._browser.session.send("Browser.setVideoRecordingOptions", {
384
- options: void 0,
385
- browserContextId: this._browserContextId
386
- });
387
- }
376
+ if (this._options.recordVideo)
377
+ await Promise.all(this._ffPages().map((ffPage) => ffPage._page.screencast.stopVideoRecording()));
388
378
  await this._browser.close({ reason });
389
379
  } else {
390
380
  await this._browser.session.send("Browser.removeBrowserContext", { browserContextId: this._browserContextId });
@@ -90,11 +90,6 @@ class FFSession extends import_events.EventEmitter {
90
90
  this._connection = connection;
91
91
  this._sessionId = sessionId;
92
92
  this._rawSend = rawSend;
93
- this.on = super.on;
94
- this.addListener = super.addListener;
95
- this.off = super.removeListener;
96
- this.removeListener = super.removeListener;
97
- this.once = super.once;
98
93
  }
99
94
  markAsCrashed() {
100
95
  this._crashed = true;
@@ -170,9 +170,9 @@ const causeToResourceType = {
170
170
  TYPE_FONT: "font",
171
171
  TYPE_MEDIA: "media",
172
172
  TYPE_WEBSOCKET: "websocket",
173
- TYPE_CSP_REPORT: "other",
173
+ TYPE_CSP_REPORT: "cspreport",
174
174
  TYPE_XSLT: "other",
175
- TYPE_BEACON: "other",
175
+ TYPE_BEACON: "beacon",
176
176
  TYPE_FETCH: "fetch",
177
177
  TYPE_IMAGESET: "image",
178
178
  TYPE_WEB_MANIFEST: "manifest"
@@ -37,14 +37,13 @@ var dialog = __toESM(require("../dialog"));
37
37
  var dom = __toESM(require("../dom"));
38
38
  var import_page = require("../page");
39
39
  var import_page2 = require("../page");
40
- var import_ffAccessibility = require("./ffAccessibility");
41
40
  var import_ffConnection = require("./ffConnection");
42
41
  var import_ffExecutionContext = require("./ffExecutionContext");
43
42
  var import_ffInput = require("./ffInput");
44
43
  var import_ffNetworkManager = require("./ffNetworkManager");
45
- var import_debugLogger = require("../utils/debugLogger");
46
44
  var import_stackTrace = require("../../utils/isomorphic/stackTrace");
47
45
  var import_errors = require("../errors");
46
+ var import_debugLogger = require("../utils/debugLogger");
48
47
  const UTILITY_WORLD_NAME = "__playwright_utility_world__";
49
48
  class FFPage {
50
49
  constructor(session, browserContext, opener) {
@@ -84,13 +83,16 @@ class FFPage {
84
83
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.workerDestroyed", this._onWorkerDestroyed.bind(this)),
85
84
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.dispatchMessageFromWorker", this._onDispatchMessageFromWorker.bind(this)),
86
85
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.crashed", this._onCrashed.bind(this)),
87
- import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.videoRecordingStarted", this._onVideoRecordingStarted.bind(this)),
88
86
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketCreated", this._onWebSocketCreated.bind(this)),
89
87
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketClosed", this._onWebSocketClosed.bind(this)),
90
88
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketFrameReceived", this._onWebSocketFrameReceived.bind(this)),
91
89
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketFrameSent", this._onWebSocketFrameSent.bind(this)),
92
90
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.screencastFrame", this._onScreencastFrame.bind(this))
93
91
  ];
92
+ const screencast = this._page.screencast;
93
+ const videoOptions = screencast.launchVideoRecorder();
94
+ if (videoOptions)
95
+ screencast.startVideoRecording(videoOptions).catch((e) => import_debugLogger.debugLogger.log("error", e));
94
96
  this._session.once("Page.ready", () => {
95
97
  if (this._reportedAsNew)
96
98
  return;
@@ -201,7 +203,7 @@ class FFPage {
201
203
  const context = this._contextIdToContext.get(executionContextId);
202
204
  if (!context)
203
205
  return;
204
- this._page.addConsoleMessage(type === "warn" ? "warning" : type, args.map((arg) => (0, import_ffExecutionContext.createHandle)(context, arg)), location);
206
+ this._page.addConsoleMessage(null, type === "warn" ? "warning" : type, args.map((arg) => (0, import_ffExecutionContext.createHandle)(context, arg)), location);
205
207
  }
206
208
  _onDialogOpened(params) {
207
209
  this._page.browserContext.dialogManager.dialogDidOpen(new dialog.Dialog(
@@ -246,11 +248,12 @@ class FFPage {
246
248
  this._page.addWorker(workerId, worker);
247
249
  workerSession.once("Runtime.executionContextCreated", (event2) => {
248
250
  worker.createExecutionContext(new import_ffExecutionContext.FFExecutionContext(workerSession, event2.executionContextId));
251
+ worker.workerScriptLoaded();
249
252
  });
250
253
  workerSession.on("Runtime.console", (event2) => {
251
254
  const { type, args, location } = event2;
252
255
  const context = worker.existingExecutionContext;
253
- this._page.addConsoleMessage(type, args.map((arg) => (0, import_ffExecutionContext.createHandle)(context, arg)), location);
256
+ this._page.addConsoleMessage(worker, type, args.map((arg) => (0, import_ffExecutionContext.createHandle)(context, arg)), location);
254
257
  });
255
258
  }
256
259
  _onWorkerDestroyed(event) {
@@ -272,11 +275,8 @@ class FFPage {
272
275
  this._session.markAsCrashed();
273
276
  this._page._didCrash();
274
277
  }
275
- _onVideoRecordingStarted(event) {
276
- this._browserContext._browser._videoStarted(this._browserContext, event.screencastId, event.file, this._page.waitForInitializedOrError());
277
- }
278
278
  didClose() {
279
- this._markAsError(new import_errors.TargetClosedError());
279
+ this._markAsError(new import_errors.TargetClosedError(this._page.closeReason()));
280
280
  this._session.dispose();
281
281
  import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
282
282
  this._networkManager.dispose();
@@ -417,24 +417,21 @@ class FFPage {
417
417
  throw e;
418
418
  });
419
419
  }
420
- async setScreencastOptions(options) {
421
- if (options) {
422
- const { screencastId } = await this._session.send("Page.startScreencast", options);
423
- this._screencastId = screencastId;
424
- } else {
425
- await this._session.send("Page.stopScreencast");
426
- }
420
+ async startScreencast(options) {
421
+ await this._session.send("Page.startScreencast", options);
422
+ }
423
+ async stopScreencast() {
424
+ await this._session.sendMayFail("Page.stopScreencast");
427
425
  }
428
426
  _onScreencastFrame(event) {
429
- if (!this._screencastId)
430
- return;
431
- const screencastId = this._screencastId;
432
- this._page.throttleScreencastFrameAck(() => {
433
- this._session.send("Page.screencastFrameAck", { screencastId }).catch((e) => import_debugLogger.debugLogger.log("error", e));
427
+ this._page.screencast.throttleFrameAck(() => {
428
+ this._session.sendMayFail("Page.screencastFrameAck");
434
429
  });
435
430
  const buffer = Buffer.from(event.data, "base64");
436
431
  this._page.emit(import_page2.Page.Events.ScreencastFrame, {
437
432
  buffer,
433
+ frameSwapWallTime: event.timestamp * 1e3,
434
+ // timestamp is in seconds, we need to convert to milliseconds.
438
435
  width: event.deviceWidth,
439
436
  height: event.deviceHeight
440
437
  });
@@ -468,9 +465,6 @@ class FFPage {
468
465
  throw new Error(dom.kUnableToAdoptErrorMessage);
469
466
  return (0, import_ffExecutionContext.createHandle)(to, result.remoteObject);
470
467
  }
471
- async getAccessibilityTree(needle) {
472
- return (0, import_ffAccessibility.getAccessibilityTree)(this._session, needle);
473
- }
474
468
  async inputActionEpilogue() {
475
469
  }
476
470
  async resetForReuse(progress) {
@@ -39,21 +39,30 @@ var import_ascii = require("../utils/ascii");
39
39
  var import_browserType = require("../browserType");
40
40
  var import_manualPromise = require("../../utils/isomorphic/manualPromise");
41
41
  class Firefox extends import_browserType.BrowserType {
42
- constructor(parent) {
42
+ constructor(parent, bidiFirefox) {
43
43
  super(parent, "firefox");
44
+ this._bidiFirefox = bidiFirefox;
45
+ }
46
+ launch(progress, options, protocolLogger) {
47
+ if (options.channel?.startsWith("moz-"))
48
+ return this._bidiFirefox.launch(progress, options, protocolLogger);
49
+ return super.launch(progress, options, protocolLogger);
50
+ }
51
+ async launchPersistentContext(progress, userDataDir, options) {
52
+ if (options.channel?.startsWith("moz-"))
53
+ return this._bidiFirefox.launchPersistentContext(progress, userDataDir, options);
54
+ return super.launchPersistentContext(progress, userDataDir, options);
44
55
  }
45
56
  connectToTransport(transport, options) {
46
57
  return import_ffBrowser.FFBrowser.connect(this.attribution.playwright, transport, options);
47
58
  }
48
- doRewriteStartupLog(error) {
49
- if (!error.logs)
50
- return error;
51
- if (error.logs.includes(`as root in a regular user's session is not supported.`))
52
- error.logs = "\n" + (0, import_ascii.wrapInASCIIBox)(`Firefox is unable to launch if the $HOME folder isn't owned by the current user.
59
+ doRewriteStartupLog(logs) {
60
+ if (logs.includes(`as root in a regular user's session is not supported.`))
61
+ logs = "\n" + (0, import_ascii.wrapInASCIIBox)(`Firefox is unable to launch if the $HOME folder isn't owned by the current user.
53
62
  Workaround: Set the HOME=/root environment variable${process.env.GITHUB_ACTION ? " in your GitHub Actions workflow file" : ""} when running Playwright.`, 1);
54
- if (error.logs.includes("no DISPLAY environment variable specified"))
55
- error.logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
56
- return error;
63
+ if (logs.includes("no DISPLAY environment variable specified"))
64
+ logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
65
+ return logs;
57
66
  }
58
67
  amendEnvironment(env) {
59
68
  if (!import_path.default.isAbsolute(import_os.default.homedir()))
@@ -51,7 +51,9 @@ class FrameSelectors {
51
51
  if (!resolved)
52
52
  throw new Error(`Failed to find frame for selector "${selector}"`);
53
53
  return await resolved.injected.evaluateHandle((injected, { info, scope: scope2 }) => {
54
- return injected.querySelectorAll(info.parsed, scope2 || document);
54
+ const elements = injected.querySelectorAll(info.parsed, scope2 || document);
55
+ injected.checkDeprecatedSelectorUsage(info.parsed, elements);
56
+ return elements;
55
57
  }, { info: resolved.info, scope: resolved.scope });
56
58
  }
57
59
  async queryCount(selector, options) {
@@ -60,7 +62,9 @@ class FrameSelectors {
60
62
  throw new Error(`Failed to find frame for selector "${selector}"`);
61
63
  await options.__testHookBeforeQuery?.();
62
64
  return await resolved.injected.evaluate((injected, { info }) => {
63
- return injected.querySelectorAll(info.parsed, document).length;
65
+ const elements = injected.querySelectorAll(info.parsed, document);
66
+ injected.checkDeprecatedSelectorUsage(info.parsed, elements);
67
+ return elements.length;
64
68
  }, { info: resolved.info });
65
69
  }
66
70
  async queryAll(selector, scope) {
@@ -68,7 +72,9 @@ class FrameSelectors {
68
72
  if (!resolved)
69
73
  return [];
70
74
  const arrayHandle = await resolved.injected.evaluateHandle((injected, { info, scope: scope2 }) => {
71
- return injected.querySelectorAll(info.parsed, scope2 || document);
75
+ const elements = injected.querySelectorAll(info.parsed, scope2 || document);
76
+ injected.checkDeprecatedSelectorUsage(info.parsed, elements);
77
+ return elements;
72
78
  }, { info: resolved.info, scope: resolved.scope });
73
79
  const properties = await arrayHandle.getProperties();
74
80
  arrayHandle.dispose();
@@ -90,10 +96,8 @@ class FrameSelectors {
90
96
  const match = body.match(/^f(\d+)e\d+$/);
91
97
  if (!match)
92
98
  return frame;
93
- const frameIndex = +match[1];
94
- const page = this.frame._page;
95
- const frameId = page.lastSnapshotFrameIds[frameIndex - 1];
96
- const jumptToFrame = frameId ? page.frameManager.frame(frameId) : null;
99
+ const frameSeq = +match[1];
100
+ const jumptToFrame = this.frame._page.frameManager.frames().find((frame2) => frame2.seq === frameSeq);
97
101
  if (!jumptToFrame)
98
102
  throw new import_selectorParser.InvalidSelectorError(`Invalid frame in aria-ref selector "${selector}"`);
99
103
  return jumptToFrame;
@@ -160,6 +164,7 @@ class FrameSelectors {
160
164
  if (!resolved)
161
165
  return;
162
166
  const context = await resolved.frame._context(options?.mainWorld ? "main" : resolved.info.world);
167
+ if (!context) throw new Error("Frame was detached");
163
168
  const injected = await context.injectedScript();
164
169
  return { injected, info: resolved.info, frame: resolved.frame, scope: resolved.scope };
165
170
  }
@@ -289,7 +294,7 @@ class FrameSelectors {
289
294
  }
290
295
  for (const child of queryingElement.children || []) {
291
296
  const childrenNodeIndex = queryingElement.children.indexOf(child);
292
- const childIndex = this._findElementPositionInDomTree(element, child, documentScope, currentIndex + childrenNodeIndex.toString());
297
+ const childIndex = this._findElementPositionInDomTree(element, child, documentScope, currentIndex + "." + childrenNodeIndex.toString());
293
298
  if (childIndex !== null) return childIndex;
294
299
  }
295
300
  if (queryingElement.shadowRoots && Array.isArray(queryingElement.shadowRoots)) {
@@ -299,6 +304,11 @@ class FrameSelectors {
299
304
  const childIndex = this._findElementPositionInDomTree(element, shadowRootHandle, documentScope, currentIndex);
300
305
  if (childIndex !== null) return childIndex;
301
306
  }
307
+ for (const shadowChild of shadowRoot.children || []) {
308
+ const shadowChildIndex = (shadowRoot.children || []).indexOf(shadowChild);
309
+ const childIndex = this._findElementPositionInDomTree(element, shadowChild, documentScope, currentIndex + "." + shadowChildIndex.toString());
310
+ if (childIndex !== null) return childIndex;
311
+ }
302
312
  }
303
313
  }
304
314
  return null;