patchright-core 1.52.5 → 1.55.0

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 (218) hide show
  1. package/ThirdPartyNotices.txt +65 -123
  2. package/bin/reinstall_chrome_beta_mac.sh +1 -1
  3. package/bin/reinstall_chrome_stable_mac.sh +1 -1
  4. package/bin/reinstall_msedge_beta_mac.sh +1 -1
  5. package/bin/reinstall_msedge_dev_mac.sh +1 -1
  6. package/bin/reinstall_msedge_stable_mac.sh +1 -1
  7. package/browsers.json +14 -14
  8. package/index.js +1 -1
  9. package/lib/androidServerImpl.js +4 -2
  10. package/lib/browserServerImpl.js +47 -12
  11. package/lib/cli/program.js +116 -50
  12. package/lib/cli/programWithTestStub.js +1 -1
  13. package/lib/client/android.js +30 -34
  14. package/lib/client/browser.js +54 -17
  15. package/lib/client/browserContext.js +67 -71
  16. package/lib/client/browserType.js +25 -34
  17. package/lib/client/channelOwner.js +20 -24
  18. package/lib/client/connection.js +6 -10
  19. package/lib/client/electron.js +8 -3
  20. package/lib/client/elementHandle.js +18 -21
  21. package/lib/client/fetch.js +5 -3
  22. package/lib/client/frame.js +54 -32
  23. package/lib/client/input.js +3 -1
  24. package/lib/client/jsHandle.js +4 -0
  25. package/lib/client/localUtils.js +0 -1
  26. package/lib/client/locator.js +30 -26
  27. package/lib/client/network.js +5 -12
  28. package/lib/client/page.js +32 -32
  29. package/lib/client/playwright.js +6 -16
  30. package/lib/client/selectors.js +18 -38
  31. package/lib/client/timeoutSettings.js +12 -8
  32. package/lib/client/tracing.js +24 -20
  33. package/lib/client/waiter.js +2 -2
  34. package/lib/client/webSocket.js +4 -22
  35. package/lib/generated/bindingsControllerSource.js +28 -0
  36. package/lib/generated/clockSource.js +1 -1
  37. package/lib/generated/injectedScriptSource.js +1 -1
  38. package/lib/generated/pollingRecorderSource.js +1 -1
  39. package/lib/generated/storageScriptSource.js +28 -0
  40. package/lib/generated/utilityScriptSource.js +1 -1
  41. package/lib/generated/webSocketMockSource.js +12 -50
  42. package/lib/inProcessFactory.js +9 -6
  43. package/lib/outofprocess.js +0 -2
  44. package/lib/protocol/validator.js +421 -345
  45. package/lib/protocol/validatorPrimitives.js +18 -4
  46. package/lib/remote/playwrightConnection.js +29 -166
  47. package/lib/remote/playwrightServer.js +233 -35
  48. package/lib/server/android/android.js +97 -83
  49. package/lib/server/android/backendAdb.js +0 -2
  50. package/lib/server/bidi/bidiBrowser.js +139 -73
  51. package/lib/server/bidi/bidiChromium.js +23 -22
  52. package/lib/server/bidi/bidiExecutionContext.js +2 -1
  53. package/lib/server/bidi/bidiFirefox.js +17 -14
  54. package/lib/server/bidi/bidiInput.js +22 -22
  55. package/lib/server/bidi/bidiNetworkManager.js +8 -11
  56. package/lib/server/bidi/bidiPage.js +42 -86
  57. package/lib/server/bidi/third_party/bidiProtocol.js +5 -133
  58. package/lib/server/bidi/third_party/bidiProtocolCore.js +179 -0
  59. package/lib/server/{dispatchers/selectorsDispatcher.js → bidi/third_party/bidiProtocolPermissions.js} +20 -18
  60. package/lib/server/browser.js +30 -21
  61. package/lib/server/browserContext.js +203 -165
  62. package/lib/server/browserType.js +109 -107
  63. package/lib/server/chromium/chromium.js +84 -69
  64. package/lib/server/chromium/chromiumSwitches.js +13 -20
  65. package/lib/server/chromium/crBrowser.js +74 -40
  66. package/lib/server/chromium/crConnection.js +8 -9
  67. package/lib/server/chromium/crCoverage.js +11 -8
  68. package/lib/server/chromium/crDragDrop.js +25 -20
  69. package/lib/server/chromium/crExecutionContext.js +2 -1
  70. package/lib/server/chromium/crInput.js +32 -29
  71. package/lib/server/chromium/crNetworkManager.js +43 -31
  72. package/lib/server/chromium/crPage.js +98 -72
  73. package/lib/server/chromium/crServiceWorker.js +13 -18
  74. package/lib/server/chromium/videoRecorder.js +10 -18
  75. package/lib/server/clock.js +51 -39
  76. package/lib/server/codegen/csharp.js +10 -5
  77. package/lib/server/codegen/java.js +1 -1
  78. package/lib/server/codegen/javascript.js +1 -1
  79. package/lib/server/codegen/jsonl.js +2 -1
  80. package/lib/server/codegen/language.js +22 -1
  81. package/lib/server/codegen/languages.js +4 -4
  82. package/lib/server/codegen/python.js +1 -1
  83. package/lib/server/cookieStore.js +3 -1
  84. package/lib/server/debugController.js +105 -71
  85. package/lib/server/debugger.js +6 -23
  86. package/lib/server/deviceDescriptorsSource.json +237 -127
  87. package/lib/server/dialog.js +50 -6
  88. package/lib/server/dispatchers/androidDispatcher.js +77 -62
  89. package/lib/server/dispatchers/artifactDispatcher.js +18 -18
  90. package/lib/server/dispatchers/browserContextDispatcher.js +141 -91
  91. package/lib/server/dispatchers/browserDispatcher.js +55 -88
  92. package/lib/server/dispatchers/browserTypeDispatcher.js +18 -9
  93. package/lib/server/dispatchers/cdpSessionDispatcher.js +4 -4
  94. package/lib/server/dispatchers/debugControllerDispatcher.js +12 -21
  95. package/lib/server/dispatchers/dialogDispatcher.js +4 -4
  96. package/lib/server/dispatchers/dispatcher.js +78 -53
  97. package/lib/server/dispatchers/electronDispatcher.js +19 -20
  98. package/lib/server/dispatchers/elementHandlerDispatcher.js +83 -93
  99. package/lib/server/dispatchers/frameDispatcher.js +98 -101
  100. package/lib/server/dispatchers/jsHandleDispatcher.js +21 -16
  101. package/lib/server/dispatchers/jsonPipeDispatcher.js +4 -4
  102. package/lib/server/dispatchers/localUtilsDispatcher.js +53 -59
  103. package/lib/server/dispatchers/networkDispatchers.js +41 -35
  104. package/lib/server/dispatchers/pageDispatcher.js +156 -107
  105. package/lib/server/dispatchers/playwrightDispatcher.js +37 -25
  106. package/lib/server/dispatchers/streamDispatcher.js +15 -8
  107. package/lib/server/dispatchers/tracingDispatcher.js +22 -13
  108. package/lib/server/dispatchers/webSocketRouteDispatcher.js +46 -35
  109. package/lib/server/dispatchers/writableStreamDispatcher.js +16 -10
  110. package/lib/server/dom.js +198 -266
  111. package/lib/server/download.js +3 -3
  112. package/lib/server/electron/electron.js +96 -103
  113. package/lib/server/electron/loader.js +1 -1
  114. package/lib/server/fetch.js +22 -41
  115. package/lib/server/fileUploadUtils.js +1 -1
  116. package/lib/server/firefox/ffBrowser.js +79 -55
  117. package/lib/server/firefox/ffExecutionContext.js +2 -1
  118. package/lib/server/firefox/ffInput.js +23 -23
  119. package/lib/server/firefox/ffNetworkManager.js +8 -6
  120. package/lib/server/firefox/ffPage.js +39 -36
  121. package/lib/server/firefox/firefox.js +9 -10
  122. package/lib/server/frameSelectors.js +63 -20
  123. package/lib/server/frames.js +495 -555
  124. package/lib/server/har/harRecorder.js +1 -1
  125. package/lib/server/har/harTracer.js +4 -2
  126. package/lib/server/helper.js +3 -7
  127. package/lib/server/index.js +0 -3
  128. package/lib/server/input.js +47 -54
  129. package/lib/server/instrumentation.js +8 -14
  130. package/lib/server/javascript.js +8 -16
  131. package/lib/server/launchApp.js +48 -30
  132. package/lib/server/localUtils.js +45 -38
  133. package/lib/server/network.js +44 -10
  134. package/lib/server/page.js +232 -177
  135. package/lib/server/pageBinding.js +6 -7
  136. package/lib/server/playwright.js +4 -14
  137. package/lib/server/progress.js +57 -49
  138. package/lib/server/recorder/recorderApp.js +298 -95
  139. package/lib/server/recorder/recorderRunner.js +23 -24
  140. package/lib/server/recorder/recorderSignalProcessor.js +83 -0
  141. package/lib/server/recorder/recorderUtils.js +67 -10
  142. package/lib/server/recorder.js +284 -146
  143. package/lib/server/registry/index.js +83 -48
  144. package/lib/server/registry/nativeDeps.js +175 -0
  145. package/lib/server/registry/oopDownloadBrowserMain.js +1 -1
  146. package/lib/server/screenshotter.js +84 -83
  147. package/lib/server/selectors.js +12 -12
  148. package/lib/server/socksClientCertificatesInterceptor.js +198 -136
  149. package/lib/server/trace/recorder/snapshotter.js +12 -19
  150. package/lib/server/trace/recorder/tracing.js +36 -27
  151. package/lib/server/trace/viewer/traceViewer.js +11 -20
  152. package/lib/server/transport.js +20 -22
  153. package/lib/server/utils/comparators.js +2 -2
  154. package/lib/server/utils/debug.js +3 -8
  155. package/lib/server/utils/debugLogger.js +8 -0
  156. package/lib/server/utils/hostPlatform.js +3 -1
  157. package/lib/server/utils/network.js +35 -25
  158. package/lib/server/utils/nodePlatform.js +1 -1
  159. package/lib/server/utils/processLauncher.js +4 -1
  160. package/lib/server/utils/wsServer.js +11 -17
  161. package/lib/server/webkit/webkit.js +5 -2
  162. package/lib/server/webkit/wkBrowser.js +51 -28
  163. package/lib/server/webkit/wkExecutionContext.js +2 -1
  164. package/lib/server/webkit/wkInput.js +25 -25
  165. package/lib/server/webkit/wkInterceptableRequest.js +1 -1
  166. package/lib/server/webkit/wkPage.js +80 -59
  167. package/lib/server/webkit/wkProvisionalPage.js +1 -1
  168. package/lib/server/webkit/wkWorkers.js +7 -7
  169. package/lib/utils/isomorphic/ariaSnapshot.js +13 -7
  170. package/lib/utils/isomorphic/cssParser.js +1 -2
  171. package/lib/utils/isomorphic/locatorGenerators.js +18 -0
  172. package/lib/utils/isomorphic/manualPromise.js +1 -2
  173. package/lib/utils/isomorphic/mimeType.js +1 -2
  174. package/lib/utils/isomorphic/multimap.js +1 -2
  175. package/lib/utils/isomorphic/oldUtilityScriptSerializers.js +248 -0
  176. package/lib/utils/isomorphic/protocolFormatter.js +78 -0
  177. package/lib/utils/isomorphic/protocolMetainfo.js +318 -0
  178. package/lib/utils/isomorphic/selectorParser.js +3 -4
  179. package/lib/utils/isomorphic/stringUtils.js +3 -24
  180. package/lib/utils/isomorphic/time.js +9 -4
  181. package/lib/utils/isomorphic/timeoutRunner.js +3 -4
  182. package/lib/utils/isomorphic/traceUtils.js +2 -3
  183. package/lib/utils/isomorphic/urlMatch.js +21 -7
  184. package/lib/utils/isomorphic/utilityScriptSerializers.js +208 -205
  185. package/lib/utils.js +8 -2
  186. package/lib/utilsBundleImpl/index.js +160 -150
  187. package/lib/vite/htmlReport/index.html +17 -17
  188. package/lib/vite/recorder/assets/{codeMirrorModule-CXVeovup.js → codeMirrorModule-DzQ0k89p.js} +1 -1
  189. package/lib/vite/recorder/assets/{index-eHBmevrY.css → index-CI4HQ-Zb.css} +1 -1
  190. package/lib/vite/recorder/assets/index-D7C7daHH.js +184 -0
  191. package/lib/vite/recorder/index.html +3 -3
  192. package/lib/vite/traceViewer/assets/{codeMirrorModule-_GLjJL-7.js → codeMirrorModule-Di48jgWx.js} +1 -1
  193. package/lib/vite/traceViewer/assets/defaultSettingsView-szBn8781.js +256 -0
  194. package/lib/vite/traceViewer/defaultSettingsView.DVJHpiGt.css +1 -0
  195. package/lib/vite/traceViewer/index.BFsek2M6.css +1 -0
  196. package/lib/vite/traceViewer/index.DQvXoPLL.js +2 -0
  197. package/lib/vite/traceViewer/index.html +6 -6
  198. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  199. package/lib/vite/traceViewer/uiMode.dBV3oN9h.js +5 -0
  200. package/lib/vite/traceViewer/uiMode.html +4 -4
  201. package/lib/zipBundleImpl.js +4 -4
  202. package/package.json +1 -1
  203. package/types/protocol.d.ts +712 -107
  204. package/types/types.d.ts +128 -17
  205. package/lib/generated/consoleApiSource.js +0 -28
  206. package/lib/protocol/debug.js +0 -211
  207. package/lib/server/recorder/contextRecorder.js +0 -286
  208. package/lib/server/recorder/recorderCollection.js +0 -116
  209. package/lib/server/recorder/recorderFrontend.js +0 -16
  210. package/lib/server/storageScript.js +0 -154
  211. package/lib/server/timeoutSettings.js +0 -89
  212. package/lib/utils/isomorphic/builtins.js +0 -86
  213. package/lib/vite/recorder/assets/index-BsWQsSGl.js +0 -184
  214. package/lib/vite/traceViewer/assets/defaultSettingsView-DtCQiGHe.js +0 -265
  215. package/lib/vite/traceViewer/defaultSettingsView.QdHITyLI.css +0 -1
  216. package/lib/vite/traceViewer/index.CFOW-Ezb.css +0 -1
  217. package/lib/vite/traceViewer/index.cFZzK9RN.js +0 -2
  218. package/lib/vite/traceViewer/uiMode.XVPIqBeS.js +0 -5
@@ -36,7 +36,6 @@ var import_events = require("events");
36
36
  var import_fs = __toESM(require("fs"));
37
37
  var import_os = __toESM(require("os"));
38
38
  var import_path = __toESM(require("path"));
39
- var import_timeoutSettings = require("../timeoutSettings");
40
39
  var import_pipeTransport = require("../utils/pipeTransport");
41
40
  var import_crypto = require("../utils/crypto");
42
41
  var import_debug = require("../utils/debug");
@@ -60,20 +59,15 @@ class Android extends import_instrumentation.SdkObject {
60
59
  super(parent, "android");
61
60
  this._devices = /* @__PURE__ */ new Map();
62
61
  this._backend = backend;
63
- this._timeoutSettings = new import_timeoutSettings.TimeoutSettings();
64
62
  }
65
- setDefaultTimeout(timeout) {
66
- this._timeoutSettings.setDefaultTimeout(timeout);
67
- }
68
- async devices(options) {
69
- const devices = (await this._backend.devices(options)).filter((d) => d.status === "device");
63
+ async devices(progress, options) {
64
+ const devices = (await progress.race(this._backend.devices(options))).filter((d) => d.status === "device");
70
65
  const newSerials = /* @__PURE__ */ new Set();
71
66
  for (const d of devices) {
72
67
  newSerials.add(d.serial);
73
68
  if (this._devices.has(d.serial))
74
69
  continue;
75
- const device = await AndroidDevice.create(this, d, options);
76
- this._devices.set(d.serial, device);
70
+ await progress.race(AndroidDevice.create(this, d, options).then((device) => this._devices.set(d.serial, device)));
77
71
  }
78
72
  for (const d of this._devices.keys()) {
79
73
  if (!newSerials.has(d))
@@ -98,7 +92,7 @@ class AndroidDevice extends import_instrumentation.SdkObject {
98
92
  this.model = model;
99
93
  this.serial = backend.serial;
100
94
  this._options = options;
101
- this._timeoutSettings = new import_timeoutSettings.TimeoutSettings(android._timeoutSettings);
95
+ this.logName = "browser";
102
96
  }
103
97
  static {
104
98
  this.Events = {
@@ -124,16 +118,13 @@ class AndroidDevice extends import_instrumentation.SdkObject {
124
118
  };
125
119
  poll();
126
120
  }
127
- setDefaultTimeout(timeout) {
128
- this._timeoutSettings.setDefaultTimeout(timeout);
129
- }
130
121
  async shell(command) {
131
122
  const result = await this._backend.runCommand(`shell:${command}`);
132
123
  await this._refreshWebViews();
133
124
  return result;
134
125
  }
135
- async open(command) {
136
- return await this._backend.open(`${command}`);
126
+ async open(progress, command) {
127
+ return await this._open(progress, command);
137
128
  }
138
129
  async screenshot() {
139
130
  return await this._backend.runCommand(`shell:screencap -p`);
@@ -141,17 +132,19 @@ class AndroidDevice extends import_instrumentation.SdkObject {
141
132
  async _driver() {
142
133
  if (this._isClosed)
143
134
  return;
144
- if (!this._driverPromise)
145
- this._driverPromise = this._installDriver();
135
+ if (!this._driverPromise) {
136
+ const controller = new import_progress.ProgressController();
137
+ this._driverPromise = controller.run((progress) => this._installDriver(progress));
138
+ }
146
139
  return this._driverPromise;
147
140
  }
148
- async _installDriver() {
141
+ async _installDriver(progress) {
149
142
  (0, import_utilsBundle.debug)("pw:android")("Stopping the old driver");
150
- await this.shell(`am force-stop com.microsoft.playwright.androiddriver`);
143
+ await progress.race(this.shell(`am force-stop com.microsoft.playwright.androiddriver`));
151
144
  if (!this._options.omitDriverInstall) {
152
145
  (0, import_utilsBundle.debug)("pw:android")("Uninstalling the old driver");
153
- await this.shell(`cmd package uninstall com.microsoft.playwright.androiddriver`);
154
- await this.shell(`cmd package uninstall com.microsoft.playwright.androiddriver.test`);
146
+ await progress.race(this.shell(`cmd package uninstall com.microsoft.playwright.androiddriver`));
147
+ await progress.race(this.shell(`cmd package uninstall com.microsoft.playwright.androiddriver.test`));
155
148
  (0, import_utilsBundle.debug)("pw:android")("Installing the new driver");
156
149
  const executable = import_registry.registry.findExecutable("android");
157
150
  const packageManagerCommand = (0, import_env.getPackageManagerExecCommand)();
@@ -159,14 +152,14 @@ class AndroidDevice extends import_instrumentation.SdkObject {
159
152
  const fullName = import_path.default.join(executable.directory, file);
160
153
  if (!import_fs.default.existsSync(fullName))
161
154
  throw new Error(`Please install Android driver apk using '${packageManagerCommand} playwright install android'`);
162
- await this.installApk(await import_fs.default.promises.readFile(fullName));
155
+ await this.installApk(progress, await progress.race(import_fs.default.promises.readFile(fullName)));
163
156
  }
164
157
  } else {
165
158
  (0, import_utilsBundle.debug)("pw:android")("Skipping the driver installation");
166
159
  }
167
160
  (0, import_utilsBundle.debug)("pw:android")("Starting the new driver");
168
161
  this.shell("am instrument -w com.microsoft.playwright.androiddriver.test/androidx.test.runner.AndroidJUnitRunner").catch((e) => (0, import_utilsBundle.debug)("pw:android")(e));
169
- const socket = await this._waitForLocalAbstract("playwright_android_driver_socket");
162
+ const socket = await this._waitForLocalAbstract(progress, "playwright_android_driver_socket");
170
163
  const transport = new import_pipeTransport.PipeTransport(socket, socket, socket, "be");
171
164
  transport.onmessage = (message) => {
172
165
  const response = JSON.parse(message);
@@ -182,21 +175,31 @@ class AndroidDevice extends import_instrumentation.SdkObject {
182
175
  };
183
176
  return transport;
184
177
  }
185
- async _waitForLocalAbstract(socketName) {
178
+ async _waitForLocalAbstract(progress, socketName) {
186
179
  let socket;
187
180
  (0, import_utilsBundle.debug)("pw:android")(`Polling the socket localabstract:${socketName}`);
188
181
  while (!socket) {
189
182
  try {
190
- socket = await this._backend.open(`localabstract:${socketName}`);
183
+ socket = await this._open(progress, `localabstract:${socketName}`);
191
184
  } catch (e) {
192
- await new Promise((f) => setTimeout(f, 250));
185
+ if ((0, import_progress.isAbortError)(e))
186
+ throw e;
187
+ await progress.wait(250);
193
188
  }
194
189
  }
195
190
  (0, import_utilsBundle.debug)("pw:android")(`Connected to localabstract:${socketName}`);
196
191
  return socket;
197
192
  }
198
193
  async send(method, params = {}) {
199
- params.timeout = this._timeoutSettings.timeout(params);
194
+ params = {
195
+ ...params,
196
+ // Patch the timeout in, just in case it's missing in one of the commands.
197
+ timeout: params.timeout || 0
198
+ };
199
+ if (params.androidSelector) {
200
+ params.selector = params.androidSelector;
201
+ delete params.androidSelector;
202
+ }
200
203
  const driver = await this._driver();
201
204
  if (!driver)
202
205
  throw new Error("Device is closed");
@@ -221,17 +224,23 @@ class AndroidDevice extends import_instrumentation.SdkObject {
221
224
  this._android._deviceClosed(this);
222
225
  this.emit(AndroidDevice.Events.Close);
223
226
  }
224
- async launchBrowser(pkg = "com.android.chrome", options) {
227
+ async launchBrowser(progress, pkg = "com.android.chrome", options) {
225
228
  (0, import_utilsBundle.debug)("pw:android")("Force-stopping", pkg);
226
229
  await this._backend.runCommand(`shell:am force-stop ${pkg}`);
227
230
  const socketName = (0, import_debug.isUnderTest)() ? "webview_devtools_remote_playwright_test" : "playwright_" + (0, import_crypto.createGuid)() + "_devtools_remote";
228
231
  const commandLine = this._defaultArgs(options, socketName).join(" ");
229
232
  (0, import_utilsBundle.debug)("pw:android")("Starting", pkg, commandLine);
230
- await this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString("base64")}" | base64 -d > /data/local/tmp/chrome-command-line`);
231
- await this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`);
232
- const browserContext = await this._connectToBrowser(socketName, options);
233
- await this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`);
234
- return browserContext;
233
+ await progress.race(this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString("base64")}" | base64 -d > /data/local/tmp/chrome-command-line`));
234
+ await progress.race(this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`));
235
+ const browserContext = await this._connectToBrowser(progress, socketName, options);
236
+ try {
237
+ await progress.race(this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`));
238
+ return browserContext;
239
+ } catch (error) {
240
+ await browserContext.close({ reason: "Failed to launch" }).catch(() => {
241
+ });
242
+ throw error;
243
+ }
235
244
  }
236
245
  _defaultArgs(options, socketName) {
237
246
  const chromeArguments = [
@@ -239,7 +248,7 @@ class AndroidDevice extends import_instrumentation.SdkObject {
239
248
  "--disable-fre",
240
249
  "--no-default-browser-check",
241
250
  `--remote-debugging-socket-name=${socketName}`,
242
- ...import_chromiumSwitches.chromiumSwitches,
251
+ ...(0, import_chromiumSwitches.chromiumSwitches)(),
243
252
  ...this._innerDefaultArgs(options)
244
253
  ];
245
254
  return chromeArguments;
@@ -260,82 +269,87 @@ class AndroidDevice extends import_instrumentation.SdkObject {
260
269
  chromeArguments.push(...args);
261
270
  return chromeArguments;
262
271
  }
263
- async connectToWebView(socketName) {
272
+ async connectToWebView(progress, socketName) {
264
273
  const webView = this._webViews.get(socketName);
265
274
  if (!webView)
266
275
  throw new Error("WebView has been closed");
267
- return await this._connectToBrowser(socketName);
268
- }
269
- async _connectToBrowser(socketName, options = {}) {
270
- const socket = await this._waitForLocalAbstract(socketName);
271
- const androidBrowser = new AndroidBrowser(this, socket);
272
- await androidBrowser._init();
273
- this._browserConnections.add(androidBrowser);
274
- const artifactsDir = await import_fs.default.promises.mkdtemp(ARTIFACTS_FOLDER);
275
- const cleanupArtifactsDir = async () => {
276
- const errors = (await (0, import_fileUtils.removeFolders)([artifactsDir])).filter(Boolean);
277
- for (let i = 0; i < (errors || []).length; ++i)
278
- (0, import_utilsBundle.debug)("pw:android")(`exception while removing ${artifactsDir}: ${errors[i]}`);
279
- };
280
- import_processLauncher.gracefullyCloseSet.add(cleanupArtifactsDir);
281
- socket.on("close", async () => {
282
- import_processLauncher.gracefullyCloseSet.delete(cleanupArtifactsDir);
283
- cleanupArtifactsDir().catch((e) => (0, import_utilsBundle.debug)("pw:android")(`could not cleanup artifacts dir: ${e}`));
284
- });
285
- const browserOptions = {
286
- name: "clank",
287
- isChromium: true,
288
- slowMo: 0,
289
- persistent: { ...options, noDefaultViewport: true },
290
- artifactsDir,
291
- downloadsPath: artifactsDir,
292
- tracesDir: artifactsDir,
293
- browserProcess: new ClankBrowserProcess(androidBrowser),
294
- proxy: options.proxy,
295
- protocolLogger: import_helper.helper.debugProtocolLogger(),
296
- browserLogsCollector: new import_debugLogger.RecentLogsCollector(),
297
- originalLaunchOptions: {}
298
- };
299
- (0, import_browserContext.validateBrowserContextOptions)(options, browserOptions);
300
- const browser = await import_crBrowser.CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions);
301
- const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), this);
302
- const defaultContext = browser._defaultContext;
303
- await controller.run(async (progress) => {
276
+ return await this._connectToBrowser(progress, socketName);
277
+ }
278
+ async _connectToBrowser(progress, socketName, options = {}) {
279
+ const socket = await this._waitForLocalAbstract(progress, socketName);
280
+ try {
281
+ const androidBrowser = new AndroidBrowser(this, socket);
282
+ await progress.race(androidBrowser._init());
283
+ this._browserConnections.add(androidBrowser);
284
+ const artifactsDir = await progress.race(import_fs.default.promises.mkdtemp(ARTIFACTS_FOLDER));
285
+ const cleanupArtifactsDir = async () => {
286
+ const errors = (await (0, import_fileUtils.removeFolders)([artifactsDir])).filter(Boolean);
287
+ for (let i = 0; i < (errors || []).length; ++i)
288
+ (0, import_utilsBundle.debug)("pw:android")(`exception while removing ${artifactsDir}: ${errors[i]}`);
289
+ };
290
+ import_processLauncher.gracefullyCloseSet.add(cleanupArtifactsDir);
291
+ socket.on("close", async () => {
292
+ import_processLauncher.gracefullyCloseSet.delete(cleanupArtifactsDir);
293
+ cleanupArtifactsDir().catch((e) => (0, import_utilsBundle.debug)("pw:android")(`could not cleanup artifacts dir: ${e}`));
294
+ });
295
+ const browserOptions = {
296
+ name: "clank",
297
+ isChromium: true,
298
+ slowMo: 0,
299
+ persistent: { ...options, noDefaultViewport: true },
300
+ artifactsDir,
301
+ downloadsPath: artifactsDir,
302
+ tracesDir: artifactsDir,
303
+ browserProcess: new ClankBrowserProcess(androidBrowser),
304
+ proxy: options.proxy,
305
+ protocolLogger: import_helper.helper.debugProtocolLogger(),
306
+ browserLogsCollector: new import_debugLogger.RecentLogsCollector(),
307
+ originalLaunchOptions: {}
308
+ };
309
+ (0, import_browserContext.validateBrowserContextOptions)(options, browserOptions);
310
+ const browser = await progress.race(import_crBrowser.CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions));
311
+ const defaultContext = browser._defaultContext;
304
312
  await defaultContext._loadDefaultContextAsIs(progress);
305
- });
306
- return defaultContext;
313
+ return defaultContext;
314
+ } catch (error) {
315
+ socket.close();
316
+ throw error;
317
+ }
318
+ }
319
+ _open(progress, command) {
320
+ return (0, import_progress.raceUncancellableOperationWithCleanup)(progress, () => this._backend.open(command), (socket) => socket.close());
307
321
  }
308
322
  webViews() {
309
323
  return [...this._webViews.values()];
310
324
  }
311
- async installApk(content, options) {
325
+ async installApk(progress, content, options) {
312
326
  const args = options && options.args ? options.args : ["-r", "-t", "-S"];
313
327
  (0, import_utilsBundle.debug)("pw:android")("Opening install socket");
314
- const installSocket = await this._backend.open(`shell:cmd package install ${args.join(" ")} ${content.length}`);
328
+ const installSocket = await this._open(progress, `shell:cmd package install ${args.join(" ")} ${content.length}`);
315
329
  (0, import_utilsBundle.debug)("pw:android")("Writing driver bytes: " + content.length);
316
- await installSocket.write(content);
317
- const success = await new Promise((f) => installSocket.on("data", f));
330
+ await progress.race(installSocket.write(content));
331
+ const success = await progress.race(new Promise((f) => installSocket.on("data", f)));
318
332
  (0, import_utilsBundle.debug)("pw:android")("Written driver bytes: " + success);
319
333
  installSocket.close();
320
334
  }
321
- async push(content, path2, mode = 420) {
322
- const socket = await this._backend.open(`sync:`);
335
+ async push(progress, content, path2, mode = 420) {
336
+ const socket = await this._open(progress, `sync:`);
323
337
  const sendHeader = async (command, length) => {
324
338
  const buffer = Buffer.alloc(command.length + 4);
325
339
  buffer.write(command, 0);
326
340
  buffer.writeUInt32LE(length, command.length);
327
- await socket.write(buffer);
341
+ await progress.race(socket.write(buffer));
328
342
  };
329
343
  const send = async (command, data) => {
330
344
  await sendHeader(command, data.length);
331
- await socket.write(data);
345
+ await progress.race(socket.write(data));
332
346
  };
333
347
  await send("SEND", Buffer.from(`${path2},${mode}`));
334
348
  const maxChunk = 65535;
335
349
  for (let i = 0; i < content.length; i += maxChunk)
336
350
  await send("DATA", content.slice(i, i + maxChunk));
337
351
  await sendHeader("DONE", Date.now() / 1e3 | 0);
338
- const result = await new Promise((f) => socket.once("data", f));
352
+ const result = await progress.race(new Promise((f) => socket.once("data", f)));
339
353
  const code = result.slice(0, 4).toString();
340
354
  if (code !== "OKAY")
341
355
  throw new Error("Could not push: " + code);
@@ -34,7 +34,6 @@ module.exports = __toCommonJS(backendAdb_exports);
34
34
  var import_events = require("events");
35
35
  var import_net = __toESM(require("net"));
36
36
  var import_assert = require("../../utils/isomorphic/assert");
37
- var import_crypto = require("../utils/crypto");
38
37
  var import_utilsBundle = require("../../utilsBundle");
39
38
  class AdbBackend {
40
39
  async devices(options = {}) {
@@ -116,7 +115,6 @@ function encodeMessage(message) {
116
115
  class BufferedSocketWrapper extends import_events.EventEmitter {
117
116
  constructor(command, socket) {
118
117
  super();
119
- this.guid = (0, import_crypto.createGuid)();
120
118
  this._buffer = Buffer.from([]);
121
119
  this._isSocket = false;
122
120
  this._isClosed = false;
@@ -40,6 +40,7 @@ var network = __toESM(require("../network"));
40
40
  var import_bidiConnection = require("./bidiConnection");
41
41
  var import_bidiNetworkManager = require("./bidiNetworkManager");
42
42
  var import_bidiPage = require("./bidiPage");
43
+ var import_page = require("../page");
43
44
  var bidi = __toESM(require("./third_party/bidiProtocol"));
44
45
  class BidiBrowser extends import_browser.Browser {
45
46
  constructor(parent, transport, options) {
@@ -57,38 +58,11 @@ class BidiBrowser extends import_browser.Browser {
57
58
  const browser = new BidiBrowser(parent, transport, options);
58
59
  if (options.__testHookOnConnectToBrowser)
59
60
  await options.__testHookOnConnectToBrowser();
60
- let proxy;
61
- if (options.proxy) {
62
- proxy = {
63
- proxyType: "manual"
64
- };
65
- const url = new URL(options.proxy.server);
66
- switch (url.protocol) {
67
- case "http:":
68
- proxy.httpProxy = url.host;
69
- break;
70
- case "https:":
71
- proxy.httpsProxy = url.host;
72
- break;
73
- case "socks4:":
74
- proxy.socksProxy = url.host;
75
- proxy.socksVersion = 4;
76
- break;
77
- case "socks5:":
78
- proxy.socksProxy = url.host;
79
- proxy.socksVersion = 5;
80
- break;
81
- default:
82
- throw new Error("Invalid proxy server protocol: " + options.proxy.server);
83
- }
84
- if (options.proxy.bypass)
85
- proxy.noProxy = options.proxy.bypass.split(",");
86
- }
87
61
  browser._bidiSessionInfo = await browser._browserSession.send("session.new", {
88
62
  capabilities: {
89
63
  alwaysMatch: {
90
- acceptInsecureCerts: false,
91
- proxy,
64
+ acceptInsecureCerts: options.persistent?.internalIgnoreHTTPSErrors || options.persistent?.ignoreHTTPSErrors,
65
+ proxy: getProxyConfiguration(options.originalLaunchOptions.proxyOverride ?? options.proxy),
92
66
  unhandledPromptBehavior: {
93
67
  default: bidi.Session.UserPromptHandlerType.Ignore
94
68
  },
@@ -117,7 +91,11 @@ class BidiBrowser extends import_browser.Browser {
117
91
  this._didClose();
118
92
  }
119
93
  async doCreateNewContext(options) {
120
- const { userContext } = await this._browserSession.send("browser.createUserContext", {});
94
+ const proxy = options.proxyOverride || options.proxy;
95
+ const { userContext } = await this._browserSession.send("browser.createUserContext", {
96
+ acceptInsecureCerts: options.internalIgnoreHTTPSErrors || options.ignoreHTTPSErrors,
97
+ proxy: getProxyConfiguration(proxy)
98
+ });
121
99
  const context = new BidiBrowserContext(this, userContext, options);
122
100
  await context._initialize();
123
101
  this._contexts.set(userContext, context);
@@ -139,12 +117,12 @@ class BidiBrowser extends import_browser.Browser {
139
117
  if (event.parent) {
140
118
  const parentFrameId = event.parent;
141
119
  for (const page2 of this._bidiPages.values()) {
142
- const parentFrame = page2._page._frameManager.frame(parentFrameId);
120
+ const parentFrame = page2._page.frameManager.frame(parentFrameId);
143
121
  if (!parentFrame)
144
122
  continue;
145
123
  page2._session.addFrameBrowsingContext(event.context);
146
- page2._page._frameManager.frameAttached(event.context, parentFrameId);
147
- const frame = page2._page._frameManager.frame(event.context);
124
+ page2._page.frameManager.frameAttached(event.context, parentFrameId);
125
+ const frame = page2._page.frameManager.frame(event.context);
148
126
  if (frame)
149
127
  frame._url = event.url;
150
128
  return;
@@ -167,10 +145,10 @@ class BidiBrowser extends import_browser.Browser {
167
145
  this._browserSession.removeFrameBrowsingContext(event.context);
168
146
  const parentFrameId = event.parent;
169
147
  for (const page of this._bidiPages.values()) {
170
- const parentFrame = page._page._frameManager.frame(parentFrameId);
148
+ const parentFrame = page._page.frameManager.frame(parentFrameId);
171
149
  if (!parentFrame)
172
150
  continue;
173
- page._page._frameManager.frameDetached(event.context);
151
+ page._page.frameManager.frameDetached(event.context);
174
152
  return;
175
153
  }
176
154
  return;
@@ -191,7 +169,8 @@ class BidiBrowser extends import_browser.Browser {
191
169
  class BidiBrowserContext extends import_browserContext.BrowserContext {
192
170
  constructor(browser, browserContextId, options) {
193
171
  super(browser, options, browserContextId);
194
- this._initScriptIds = [];
172
+ this._originToPermissions = /* @__PURE__ */ new Map();
173
+ this._initScriptIds = /* @__PURE__ */ new Map();
195
174
  this._authenticateProxyViaHeader();
196
175
  }
197
176
  _bidiPages() {
@@ -199,42 +178,23 @@ class BidiBrowserContext extends import_browserContext.BrowserContext {
199
178
  }
200
179
  async _initialize() {
201
180
  const promises = [
202
- super._initialize(),
203
- this._installMainBinding()
181
+ super._initialize()
204
182
  ];
205
- if (this._options.viewport) {
206
- promises.push(this._browser._browserSession.send("browsingContext.setViewport", {
207
- viewport: {
208
- width: this._options.viewport.width,
209
- height: this._options.viewport.height
210
- },
211
- devicePixelRatio: this._options.deviceScaleFactor || 1,
183
+ promises.push(this.doUpdateDefaultViewport());
184
+ if (this._options.geolocation)
185
+ promises.push(this.setGeolocation(this._options.geolocation));
186
+ if (this._options.locale) {
187
+ promises.push(this._browser._browserSession.send("emulation.setLocaleOverride", {
188
+ locale: this._options.locale,
212
189
  userContexts: [this._userContextId()]
213
190
  }));
214
191
  }
215
192
  await Promise.all(promises);
216
193
  }
217
- // TODO: consider calling this only when bindings are added.
218
- async _installMainBinding() {
219
- const functionDeclaration = import_bidiPage.addMainBinding.toString();
220
- const args = [{
221
- type: "channel",
222
- value: {
223
- channel: import_bidiPage.kPlaywrightBindingChannel,
224
- ownership: bidi.Script.ResultOwnership.Root
225
- }
226
- }];
227
- await this._browser._browserSession.send("script.addPreloadScript", {
228
- functionDeclaration,
229
- arguments: args,
230
- userContexts: [this._userContextId()]
231
- });
232
- }
233
194
  possiblyUninitializedPages() {
234
195
  return this._bidiPages().map((bidiPage) => bidiPage._page);
235
196
  }
236
197
  async doCreateNewPage() {
237
- (0, import_browserContext.assertBrowserContextIsNotOwned)(this);
238
198
  const { context } = await this._browser._browserSession.send("browsingContext.create", {
239
199
  type: bidi.BrowsingContext.CreateType.Window,
240
200
  userContext: this._browserContextId
@@ -287,38 +247,114 @@ class BidiBrowserContext extends import_browserContext.BrowserContext {
287
247
  );
288
248
  }
289
249
  async doGrantPermissions(origin, permissions) {
250
+ const currentPermissions = this._originToPermissions.get(origin) || [];
251
+ const toGrant = permissions.filter((permission) => !currentPermissions.includes(permission));
252
+ this._originToPermissions.set(origin, [...currentPermissions, ...toGrant]);
253
+ await Promise.all(toGrant.map((permission) => this._setPermission(origin, permission, bidi.Permissions.PermissionState.Granted)));
290
254
  }
291
255
  async doClearPermissions() {
256
+ const currentPermissions = [...this._originToPermissions.entries()];
257
+ this._originToPermissions = /* @__PURE__ */ new Map();
258
+ await Promise.all(currentPermissions.map(([origin, permissions]) => permissions.map(
259
+ (p) => this._setPermission(origin, p, bidi.Permissions.PermissionState.Prompt)
260
+ )));
261
+ }
262
+ async _setPermission(origin, permission, state) {
263
+ await this._browser._browserSession.send("permissions.setPermission", {
264
+ descriptor: {
265
+ name: permission
266
+ },
267
+ state,
268
+ origin,
269
+ userContext: this._userContextId()
270
+ });
292
271
  }
293
272
  async setGeolocation(geolocation) {
273
+ (0, import_browserContext.verifyGeolocation)(geolocation);
274
+ this._options.geolocation = geolocation;
275
+ await this._browser._browserSession.send("emulation.setGeolocationOverride", {
276
+ coordinates: geolocation ? {
277
+ latitude: geolocation.latitude,
278
+ longitude: geolocation.longitude,
279
+ accuracy: geolocation.accuracy
280
+ } : null,
281
+ userContexts: [this._userContextId()]
282
+ });
294
283
  }
295
- async setExtraHTTPHeaders(headers) {
284
+ async doUpdateExtraHTTPHeaders() {
296
285
  }
297
286
  async setUserAgent(userAgent) {
298
287
  }
299
- async setOffline(offline) {
288
+ async doUpdateOffline() {
300
289
  }
301
290
  async doSetHTTPCredentials(httpCredentials) {
302
291
  this._options.httpCredentials = httpCredentials;
303
292
  for (const page of this.pages())
304
- await page._delegate.updateHttpCredentials();
293
+ await page.delegate.updateHttpCredentials();
305
294
  }
306
295
  async doAddInitScript(initScript) {
307
296
  const { script } = await this._browser._browserSession.send("script.addPreloadScript", {
308
297
  // TODO: remove function call from the source.
309
298
  functionDeclaration: `() => { return ${initScript.source} }`,
310
- userContexts: [this._browserContextId || "default"]
299
+ userContexts: [this._userContextId()]
311
300
  });
312
- if (!initScript.internal)
313
- this._initScriptIds.push(script);
314
- }
315
- async doRemoveNonInternalInitScripts() {
316
- const promise = Promise.all(this._initScriptIds.map((script) => this._browser._browserSession.send("script.removePreloadScript", { script })));
317
- this._initScriptIds = [];
318
- await promise;
301
+ this._initScriptIds.set(initScript, script);
302
+ }
303
+ async doRemoveInitScripts(initScripts) {
304
+ const ids = [];
305
+ for (const script of initScripts) {
306
+ const id = this._initScriptIds.get(script);
307
+ if (id)
308
+ ids.push(id);
309
+ this._initScriptIds.delete(script);
310
+ }
311
+ await Promise.all(ids.map((script) => this._browser._browserSession.send("script.removePreloadScript", { script })));
319
312
  }
320
313
  async doUpdateRequestInterception() {
321
314
  }
315
+ async doUpdateDefaultViewport() {
316
+ if (!this._options.viewport)
317
+ return;
318
+ await this._browser._browserSession.send("browsingContext.setViewport", {
319
+ viewport: {
320
+ width: this._options.viewport.width,
321
+ height: this._options.viewport.height
322
+ },
323
+ devicePixelRatio: this._options.deviceScaleFactor || 1,
324
+ userContexts: [this._userContextId()]
325
+ });
326
+ }
327
+ async doUpdateDefaultEmulatedMedia() {
328
+ }
329
+ async doExposePlaywrightBinding() {
330
+ const args = [{
331
+ type: "channel",
332
+ value: {
333
+ channel: import_bidiPage.kPlaywrightBindingChannel,
334
+ ownership: bidi.Script.ResultOwnership.Root
335
+ }
336
+ }];
337
+ const functionDeclaration = `function addMainBinding(callback) { globalThis['${import_page.PageBinding.kBindingName}'] = callback; }`;
338
+ const promises = [];
339
+ promises.push(this._browser._browserSession.send("script.addPreloadScript", {
340
+ functionDeclaration,
341
+ arguments: args,
342
+ userContexts: [this._userContextId()]
343
+ }));
344
+ promises.push(...this._bidiPages().map((page) => {
345
+ const realms = [...page._realmToContext].filter(([realm, context]) => context.world === "main").map(([realm, context]) => realm);
346
+ return Promise.all(realms.map((realm) => {
347
+ return page._session.send("script.callFunction", {
348
+ functionDeclaration,
349
+ arguments: args,
350
+ target: { realm },
351
+ awaitPromise: false,
352
+ userActivation: false
353
+ });
354
+ }));
355
+ }));
356
+ await Promise.all(promises);
357
+ }
322
358
  onClosePersistent() {
323
359
  }
324
360
  async clearCache() {
@@ -363,6 +399,36 @@ function toBidiSameSite(sameSite) {
363
399
  }
364
400
  return bidi.Network.SameSite.None;
365
401
  }
402
+ function getProxyConfiguration(proxySettings) {
403
+ if (!proxySettings)
404
+ return void 0;
405
+ const proxy = {
406
+ proxyType: "manual"
407
+ };
408
+ const url = new URL(proxySettings.server);
409
+ switch (url.protocol) {
410
+ case "http:":
411
+ proxy.httpProxy = url.host;
412
+ break;
413
+ case "https:":
414
+ proxy.sslProxy = url.host;
415
+ break;
416
+ case "socks4:":
417
+ proxy.socksProxy = url.host;
418
+ proxy.socksVersion = 4;
419
+ break;
420
+ case "socks5:":
421
+ proxy.socksProxy = url.host;
422
+ proxy.socksVersion = 5;
423
+ break;
424
+ default:
425
+ throw new Error("Invalid proxy server protocol: " + proxySettings.server);
426
+ }
427
+ const bypass = proxySettings.bypass ?? process.env.PLAYWRIGHT_PROXY_BYPASS_FOR_TESTING;
428
+ if (bypass)
429
+ proxy.noProxy = bypass.split(",");
430
+ return proxy;
431
+ }
366
432
  var Network;
367
433
  ((Network2) => {
368
434
  let SameSite;