patchright-core 1.52.5 → 1.55.1

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
@@ -50,7 +50,7 @@ import_utilsBundle.program.command("mark-docker-image [dockerImageNameTemplate]"
50
50
  (0, import_server.writeDockerVersion)(dockerImageNameTemplate).catch(logErrorAndExit);
51
51
  });
52
52
  commandWithOpenOptions("open [url]", "open page in browser specified via -b, --browser", []).action(function(url, options) {
53
- open(options, url, codegenId()).catch(logErrorAndExit);
53
+ open(options, url).catch(logErrorAndExit);
54
54
  }).addHelpText("afterAll", `
55
55
  Examples:
56
56
 
@@ -64,8 +64,8 @@ commandWithOpenOptions(
64
64
  ["--target <language>", `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit`, codegenId()],
65
65
  ["--test-id-attribute <attributeName>", "use the specified attribute to generate data test ID selectors"]
66
66
  ]
67
- ).action(function(url, options) {
68
- codegen(options, url).catch(logErrorAndExit);
67
+ ).action(async function(url, options) {
68
+ await codegen(options, url);
69
69
  }).addHelpText("afterAll", `
70
70
  Examples:
71
71
 
@@ -113,7 +113,59 @@ function checkBrowsersToInstall(args, options) {
113
113
  throw new Error(`Invalid installation targets: ${faultyArguments.map((name) => `'${name}'`).join(", ")}. Expecting one of: ${suggestedBrowsersToInstall()}`);
114
114
  return executables;
115
115
  }
116
- import_utilsBundle.program.command("install [browser...]").description("ensure browsers necessary for this version of Playwright are installed").option("--with-deps", "install system dependencies for browsers").option("--dry-run", "do not execute installation, only print information").option("--force", "force reinstall of stable browser channels").option("--only-shell", "only install headless shell when installing chromium").option("--no-shell", "do not install chromium headless shell").action(async function(args, options) {
116
+ function printInstalledBrowsers(browsers2) {
117
+ const browserPaths = /* @__PURE__ */ new Set();
118
+ for (const browser of browsers2)
119
+ browserPaths.add(browser.browserPath);
120
+ console.log(` Browsers:`);
121
+ for (const browserPath of [...browserPaths].sort())
122
+ console.log(` ${browserPath}`);
123
+ console.log(` References:`);
124
+ const references = /* @__PURE__ */ new Set();
125
+ for (const browser of browsers2)
126
+ references.add(browser.referenceDir);
127
+ for (const reference of [...references].sort())
128
+ console.log(` ${reference}`);
129
+ }
130
+ function printGroupedByPlaywrightVersion(browsers2) {
131
+ const dirToVersion = /* @__PURE__ */ new Map();
132
+ for (const browser of browsers2) {
133
+ if (dirToVersion.has(browser.referenceDir))
134
+ continue;
135
+ const packageJSON2 = require(import_path.default.join(browser.referenceDir, "package.json"));
136
+ const version = packageJSON2.version;
137
+ dirToVersion.set(browser.referenceDir, version);
138
+ }
139
+ const groupedByPlaywrightMinorVersion = /* @__PURE__ */ new Map();
140
+ for (const browser of browsers2) {
141
+ const version = dirToVersion.get(browser.referenceDir);
142
+ let entries = groupedByPlaywrightMinorVersion.get(version);
143
+ if (!entries) {
144
+ entries = [];
145
+ groupedByPlaywrightMinorVersion.set(version, entries);
146
+ }
147
+ entries.push(browser);
148
+ }
149
+ const sortedVersions = [...groupedByPlaywrightMinorVersion.keys()].sort((a, b) => {
150
+ const aComponents = a.split(".");
151
+ const bComponents = b.split(".");
152
+ const aMajor = parseInt(aComponents[0], 10);
153
+ const bMajor = parseInt(bComponents[0], 10);
154
+ if (aMajor !== bMajor)
155
+ return aMajor - bMajor;
156
+ const aMinor = parseInt(aComponents[1], 10);
157
+ const bMinor = parseInt(bComponents[1], 10);
158
+ if (aMinor !== bMinor)
159
+ return aMinor - bMinor;
160
+ return aComponents.slice(2).join(".").localeCompare(bComponents.slice(2).join("."));
161
+ });
162
+ for (const version of sortedVersions) {
163
+ console.log(`
164
+ Playwright version: ${version}`);
165
+ printInstalledBrowsers(groupedByPlaywrightMinorVersion.get(version));
166
+ }
167
+ }
168
+ import_utilsBundle.program.command("install [browser...]").description("ensure browsers necessary for this version of Playwright are installed").option("--with-deps", "install system dependencies for browsers").option("--dry-run", "do not execute installation, only print information").option("--list", "prints list of browsers from all playwright installations").option("--force", "force reinstall of stable browser channels").option("--only-shell", "only install headless shell when installing chromium").option("--no-shell", "do not install chromium headless shell").action(async function(args, options) {
117
169
  if (options.shell === false)
118
170
  options.noShell = true;
119
171
  if ((0, import_utils.isLikelyNpxGlobal)()) {
@@ -141,6 +193,8 @@ import_utilsBundle.program.command("install [browser...]").description("ensure b
141
193
  const executables = hasNoArguments ? defaultBrowsersToInstall(options) : checkBrowsersToInstall(args, options);
142
194
  if (options.withDeps)
143
195
  await import_server.registry.installDeps(executables, !!options.dryRun);
196
+ if (options.dryRun && options.list)
197
+ throw new Error(`Only one of --dry-run and --list can be specified`);
144
198
  if (options.dryRun) {
145
199
  for (const executable of executables) {
146
200
  const version = executable.browserVersion ? `version ` + executable.browserVersion : "";
@@ -154,6 +208,9 @@ import_utilsBundle.program.command("install [browser...]").description("ensure b
154
208
  }
155
209
  console.log(``);
156
210
  }
211
+ } else if (options.list) {
212
+ const browsers2 = await import_server.registry.listInstalledBrowsers();
213
+ printGroupedByPlaywrightVersion(browsers2);
157
214
  } else {
158
215
  const forceReinstall = hasNoArguments ? false : !!options.force;
159
216
  await import_server.registry.install(executables, forceReinstall);
@@ -210,7 +267,7 @@ const browsers = [
210
267
  ];
211
268
  for (const { alias, name, type } of browsers) {
212
269
  commandWithOpenOptions(`${alias} [url]`, `open page in ${name}`, []).action(function(url, options) {
213
- open({ ...options, browser: type }, url, options.target).catch(logErrorAndExit);
270
+ open({ ...options, browser: type }, url).catch(logErrorAndExit);
214
271
  }).addHelpText("afterAll", `
215
272
  Examples:
216
273
 
@@ -310,30 +367,6 @@ async function launchContext(options, extraOptions) {
310
367
  if (options.proxyBypass)
311
368
  launchOptions.proxy.bypass = options.proxyBypass;
312
369
  }
313
- const browser = await browserType.launch(launchOptions);
314
- if (process.env.PWTEST_CLI_IS_UNDER_TEST) {
315
- process._didSetSourcesForTest = (text) => {
316
- process.stdout.write("\n-------------8<-------------\n");
317
- process.stdout.write(text);
318
- process.stdout.write("\n-------------8<-------------\n");
319
- const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
320
- if (autoExitCondition && text.includes(autoExitCondition))
321
- closeBrowser();
322
- };
323
- const logs = [];
324
- require("playwright-core/lib/utilsBundle").debug.log = (...args) => {
325
- const line = require("util").format(...args) + "\n";
326
- logs.push(line);
327
- process.stderr.write(line);
328
- };
329
- browser.on("disconnected", () => {
330
- const hasCrashLine = logs.some((line) => line.includes("process did exit:") && !line.includes("process did exit: exitCode=0, signal=null"));
331
- if (hasCrashLine) {
332
- process.stderr.write("Detected browser crash.\n");
333
- (0, import_utils.gracefullyProcessExitDoNotHang)(1);
334
- }
335
- });
336
- }
337
370
  if (options.viewportSize) {
338
371
  try {
339
372
  const [width, height] = options.viewportSize.split(",").map((n) => +n);
@@ -374,7 +407,15 @@ async function launchContext(options, extraOptions) {
374
407
  contextOptions.recordHar.urlFilter = options.saveHarGlob;
375
408
  contextOptions.serviceWorkers = "block";
376
409
  }
377
- const context = await browser.newContext(contextOptions);
410
+ let browser;
411
+ let context;
412
+ if (options.userDataDir) {
413
+ context = await browserType.launchPersistentContext(options.userDataDir, { ...launchOptions, ...contextOptions });
414
+ browser = context.browser();
415
+ } else {
416
+ browser = await browserType.launch(launchOptions);
417
+ context = await browser.newContext(contextOptions);
418
+ }
378
419
  let closingBrowser = false;
379
420
  async function closeBrowser() {
380
421
  if (closingBrowser)
@@ -408,44 +449,35 @@ async function launchContext(options, extraOptions) {
408
449
  delete launchOptions.executablePath;
409
450
  delete launchOptions.handleSIGINT;
410
451
  delete contextOptions.deviceScaleFactor;
411
- return { browser, browserName: browserType.name(), context, contextOptions, launchOptions };
452
+ return { browser, browserName: browserType.name(), context, contextOptions, launchOptions, closeBrowser };
412
453
  }
413
454
  async function openPage(context, url) {
414
- const page = await context.newPage();
455
+ let page = context.pages()[0];
456
+ if (!page)
457
+ page = await context.newPage();
415
458
  if (url) {
416
459
  if (import_fs.default.existsSync(url))
417
460
  url = "file://" + import_path.default.resolve(url);
418
461
  else if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:") && !url.startsWith("data:"))
419
462
  url = "http://" + url;
420
- await page.goto(url).catch((error) => {
421
- if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
422
- } else {
423
- throw error;
424
- }
425
- });
463
+ await page.goto(url);
426
464
  }
427
465
  return page;
428
466
  }
429
- async function open(options, url, language) {
430
- const { context, launchOptions, contextOptions } = await launchContext(options, { headless: !!process.env.PWTEST_CLI_HEADLESS, executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH });
431
- await context._enableRecorder({
432
- language,
433
- launchOptions,
434
- contextOptions,
435
- device: options.device,
436
- saveStorage: options.saveStorage,
437
- handleSIGINT: false
438
- });
467
+ async function open(options, url) {
468
+ const { context } = await launchContext(options, { headless: !!process.env.PWTEST_CLI_HEADLESS, executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH });
439
469
  await openPage(context, url);
440
470
  }
441
471
  async function codegen(options, url) {
442
472
  const { target: language, output: outputFile, testIdAttribute: testIdAttributeName } = options;
443
473
  const tracesDir = import_path.default.join(import_os.default.tmpdir(), `playwright-recorder-trace-${Date.now()}`);
444
- const { context, launchOptions, contextOptions } = await launchContext(options, {
474
+ const { context, browser, launchOptions, contextOptions, closeBrowser } = await launchContext(options, {
445
475
  headless: !!process.env.PWTEST_CLI_HEADLESS,
446
476
  executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH,
447
477
  tracesDir
448
478
  });
479
+ const donePromise = new import_utils.ManualPromise();
480
+ maybeSetupTestHooks(browser, closeBrowser, donePromise);
449
481
  import_utilsBundle.dotenv.config({ path: "playwright.env" });
450
482
  await context._enableRecorder({
451
483
  language,
@@ -459,6 +491,40 @@ async function codegen(options, url) {
459
491
  handleSIGINT: false
460
492
  });
461
493
  await openPage(context, url);
494
+ donePromise.resolve();
495
+ }
496
+ async function maybeSetupTestHooks(browser, closeBrowser, donePromise) {
497
+ if (!process.env.PWTEST_CLI_IS_UNDER_TEST)
498
+ return;
499
+ const logs = [];
500
+ require("playwright-core/lib/utilsBundle").debug.log = (...args) => {
501
+ const line = require("util").format(...args) + "\n";
502
+ logs.push(line);
503
+ process.stderr.write(line);
504
+ };
505
+ browser.on("disconnected", () => {
506
+ const hasCrashLine = logs.some((line) => line.includes("process did exit:") && !line.includes("process did exit: exitCode=0, signal=null"));
507
+ if (hasCrashLine) {
508
+ process.stderr.write("Detected browser crash.\n");
509
+ (0, import_utils.gracefullyProcessExitDoNotHang)(1);
510
+ }
511
+ });
512
+ const close = async () => {
513
+ await donePromise;
514
+ await closeBrowser();
515
+ };
516
+ if (process.env.PWTEST_CLI_EXIT_AFTER_TIMEOUT) {
517
+ setTimeout(close, +process.env.PWTEST_CLI_EXIT_AFTER_TIMEOUT);
518
+ return;
519
+ }
520
+ let stdin = "";
521
+ process.stdin.on("data", (data) => {
522
+ stdin += data.toString();
523
+ if (stdin.startsWith("exit")) {
524
+ process.stdin.destroy();
525
+ close();
526
+ }
527
+ });
462
528
  }
463
529
  async function waitForPage(page, captureOptions) {
464
530
  if (captureOptions.waitForSelector) {
@@ -545,7 +611,7 @@ function commandWithOpenOptions(command, description, options) {
545
611
  let result = import_utilsBundle.program.command(command).description(description);
546
612
  for (const option of options)
547
613
  result = result.option(option[0], ...option.slice(1));
548
- return result.option("-b, --browser <browserType>", "browser to use, one of cr, chromium, ff, firefox, wk, webkit", "chromium").option("--block-service-workers", "block service workers").option("--channel <channel>", 'Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc').option("--color-scheme <scheme>", 'emulate preferred color scheme, "light" or "dark"').option("--device <deviceName>", 'emulate device, for example "iPhone 11"').option("--geolocation <coordinates>", 'specify geolocation coordinates, for example "37.819722,-122.478611"').option("--ignore-https-errors", "ignore https errors").option("--load-storage <filename>", "load context storage state from the file, previously saved with --save-storage").option("--lang <language>", 'specify language / locale, for example "en-GB"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--save-har <filename>", "save HAR file with all network activity at the end").option("--save-har-glob <glob pattern>", "filter entries in the HAR by matching url against this glob pattern").option("--save-storage <filename>", "save context storage state at the end, for later use with --load-storage").option("--timezone <time zone>", 'time zone to emulate, for example "Europe/Rome"').option("--timeout <timeout>", "timeout for Playwright actions in milliseconds, no timeout by default").option("--user-agent <ua string>", "specify user agent string").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280, 720"');
614
+ return result.option("-b, --browser <browserType>", "browser to use, one of cr, chromium, ff, firefox, wk, webkit", "chromium").option("--block-service-workers", "block service workers").option("--channel <channel>", 'Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc').option("--color-scheme <scheme>", 'emulate preferred color scheme, "light" or "dark"').option("--device <deviceName>", 'emulate device, for example "iPhone 11"').option("--geolocation <coordinates>", 'specify geolocation coordinates, for example "37.819722,-122.478611"').option("--ignore-https-errors", "ignore https errors").option("--load-storage <filename>", "load context storage state from the file, previously saved with --save-storage").option("--lang <language>", 'specify language / locale, for example "en-GB"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--save-har <filename>", "save HAR file with all network activity at the end").option("--save-har-glob <glob pattern>", "filter entries in the HAR by matching url against this glob pattern").option("--save-storage <filename>", "save context storage state at the end, for later use with --load-storage").option("--timezone <time zone>", 'time zone to emulate, for example "Europe/Rome"').option("--timeout <timeout>", "timeout for Playwright actions in milliseconds, no timeout by default").option("--user-agent <ua string>", "specify user agent string").option("--user-data-dir <directory>", "use the specified user data directory instead of a new context").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280, 720"');
549
615
  }
550
616
  function buildBasePlaywrightCLICommand(cliTargetLang) {
551
617
  switch (cliTargetLang) {
@@ -58,7 +58,7 @@ const kExternalPlaywrightTestCommands = [
58
58
  ];
59
59
  function addExternalPlaywrightTestCommands() {
60
60
  for (const [command, description] of kExternalPlaywrightTestCommands) {
61
- const playwrightTest = import_program.program.command(command).allowUnknownOption(true);
61
+ const playwrightTest = import_program.program.command(command).allowUnknownOption(true).allowExcessArguments(true);
62
62
  playwrightTest.description(`${description} Available in @playwright/test package.`);
63
63
  playwrightTest.action(async () => {
64
64
  printPlaywrightTestError(command);
@@ -46,10 +46,6 @@ class Android extends import_channelOwner.ChannelOwner {
46
46
  }
47
47
  setDefaultTimeout(timeout) {
48
48
  this._timeoutSettings.setDefaultTimeout(timeout);
49
- this._wrapApiCall(async () => {
50
- await this._channel.setDefaultTimeoutNoReply({ timeout });
51
- }, true).catch(() => {
52
- });
53
49
  }
54
50
  async devices(options = {}) {
55
51
  const { devices } = await this._channel.devices(options);
@@ -64,7 +60,7 @@ class Android extends import_channelOwner.ChannelOwner {
64
60
  return await this._wrapApiCall(async () => {
65
61
  const deadline = options.timeout ? (0, import_time.monotonicTime)() + options.timeout : 0;
66
62
  const headers = { "x-playwright-browser": "android", ...options.headers };
67
- const connectParams = { wsEndpoint, headers, slowMo: options.slowMo, timeout: options.timeout };
63
+ const connectParams = { wsEndpoint, headers, slowMo: options.slowMo, timeout: options.timeout || 0 };
68
64
  const connection = await (0, import_webSocket.connectOverWebSocket)(this._connection, connectParams);
69
65
  let device;
70
66
  connection.on("close", () => {
@@ -95,6 +91,7 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
95
91
  super(parent, type, guid, initializer);
96
92
  this._webViews = /* @__PURE__ */ new Map();
97
93
  this._shouldCloseConnectionOnClose = false;
94
+ this._android = parent;
98
95
  this.input = new AndroidInput(this);
99
96
  this._timeoutSettings = new import_timeoutSettings.TimeoutSettings(this._platform, parent._timeoutSettings);
100
97
  this._channel.on("webViewAdded", ({ webView }) => this._onWebViewAdded(webView));
@@ -117,10 +114,6 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
117
114
  }
118
115
  setDefaultTimeout(timeout) {
119
116
  this._timeoutSettings.setDefaultTimeout(timeout);
120
- this._wrapApiCall(async () => {
121
- await this._channel.setDefaultTimeoutNoReply({ timeout });
122
- }, true).catch(() => {
123
- });
124
117
  }
125
118
  serial() {
126
119
  return this._initializer.serial;
@@ -144,42 +137,42 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
144
137
  return webView;
145
138
  return await this.waitForEvent("webview", { ...options, predicate });
146
139
  }
147
- async wait(selector, options) {
148
- await this._channel.wait({ selector: toSelectorChannel(selector), ...options });
140
+ async wait(selector, options = {}) {
141
+ await this._channel.wait({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) });
149
142
  }
150
- async fill(selector, text, options) {
151
- await this._channel.fill({ selector: toSelectorChannel(selector), text, ...options });
143
+ async fill(selector, text, options = {}) {
144
+ await this._channel.fill({ androidSelector: toSelectorChannel(selector), text, ...options, timeout: this._timeoutSettings.timeout(options) });
152
145
  }
153
- async press(selector, key, options) {
146
+ async press(selector, key, options = {}) {
154
147
  await this.tap(selector, options);
155
148
  await this.input.press(key);
156
149
  }
157
- async tap(selector, options) {
158
- await this._channel.tap({ selector: toSelectorChannel(selector), ...options });
150
+ async tap(selector, options = {}) {
151
+ await this._channel.tap({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) });
159
152
  }
160
- async drag(selector, dest, options) {
161
- await this._channel.drag({ selector: toSelectorChannel(selector), dest, ...options });
153
+ async drag(selector, dest, options = {}) {
154
+ await this._channel.drag({ androidSelector: toSelectorChannel(selector), dest, ...options, timeout: this._timeoutSettings.timeout(options) });
162
155
  }
163
- async fling(selector, direction, options) {
164
- await this._channel.fling({ selector: toSelectorChannel(selector), direction, ...options });
156
+ async fling(selector, direction, options = {}) {
157
+ await this._channel.fling({ androidSelector: toSelectorChannel(selector), direction, ...options, timeout: this._timeoutSettings.timeout(options) });
165
158
  }
166
- async longTap(selector, options) {
167
- await this._channel.longTap({ selector: toSelectorChannel(selector), ...options });
159
+ async longTap(selector, options = {}) {
160
+ await this._channel.longTap({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) });
168
161
  }
169
- async pinchClose(selector, percent, options) {
170
- await this._channel.pinchClose({ selector: toSelectorChannel(selector), percent, ...options });
162
+ async pinchClose(selector, percent, options = {}) {
163
+ await this._channel.pinchClose({ androidSelector: toSelectorChannel(selector), percent, ...options, timeout: this._timeoutSettings.timeout(options) });
171
164
  }
172
- async pinchOpen(selector, percent, options) {
173
- await this._channel.pinchOpen({ selector: toSelectorChannel(selector), percent, ...options });
165
+ async pinchOpen(selector, percent, options = {}) {
166
+ await this._channel.pinchOpen({ androidSelector: toSelectorChannel(selector), percent, ...options, timeout: this._timeoutSettings.timeout(options) });
174
167
  }
175
- async scroll(selector, direction, percent, options) {
176
- await this._channel.scroll({ selector: toSelectorChannel(selector), direction, percent, ...options });
168
+ async scroll(selector, direction, percent, options = {}) {
169
+ await this._channel.scroll({ androidSelector: toSelectorChannel(selector), direction, percent, ...options, timeout: this._timeoutSettings.timeout(options) });
177
170
  }
178
- async swipe(selector, direction, percent, options) {
179
- await this._channel.swipe({ selector: toSelectorChannel(selector), direction, percent, ...options });
171
+ async swipe(selector, direction, percent, options = {}) {
172
+ await this._channel.swipe({ androidSelector: toSelectorChannel(selector), direction, percent, ...options, timeout: this._timeoutSettings.timeout(options) });
180
173
  }
181
174
  async info(selector) {
182
- return (await this._channel.info({ selector: toSelectorChannel(selector) })).info;
175
+ return (await this._channel.info({ androidSelector: toSelectorChannel(selector) })).info;
183
176
  }
184
177
  async screenshot(options = {}) {
185
178
  const { binary } = await this._channel.screenshot();
@@ -222,7 +215,10 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
222
215
  const contextOptions = await (0, import_browserContext.prepareBrowserContextParams)(this._platform, options);
223
216
  const result = await this._channel.launchBrowser(contextOptions);
224
217
  const context = import_browserContext.BrowserContext.from(result.context);
225
- context._setOptions(contextOptions, {});
218
+ const selectors = this._android._playwright.selectors;
219
+ selectors._contextsForSelectors.add(context);
220
+ context.once(import_events.Events.BrowserContext.Close, () => selectors._contextsForSelectors.delete(context));
221
+ await context._initializeHarFromOptions(options.recordHar);
226
222
  return context;
227
223
  }
228
224
  async waitForEvent(event, optionsOrPredicate = {}) {
@@ -323,8 +319,8 @@ function toSelectorChannel(selector) {
323
319
  enabled,
324
320
  focusable,
325
321
  focused,
326
- hasChild: hasChild ? { selector: toSelectorChannel(hasChild.selector) } : void 0,
327
- hasDescendant: hasDescendant ? { selector: toSelectorChannel(hasDescendant.selector), maxDepth: hasDescendant.maxDepth } : void 0,
322
+ hasChild: hasChild ? { androidSelector: toSelectorChannel(hasChild.selector) } : void 0,
323
+ hasDescendant: hasDescendant ? { androidSelector: toSelectorChannel(hasDescendant.selector), maxDepth: hasDescendant.maxDepth } : void 0,
328
324
  longClickable,
329
325
  scrollable,
330
326
  selected
@@ -36,6 +36,7 @@ class Browser extends import_channelOwner.ChannelOwner {
36
36
  this._shouldCloseConnectionOnClose = false;
37
37
  this._options = {};
38
38
  this._name = initializer.name;
39
+ this._channel.on("context", ({ context }) => this._didCreateContext(import_browserContext.BrowserContext.from(context)));
39
40
  this._channel.on("close", () => this._didClose());
40
41
  this._closedPromise = new Promise((f) => this.once(import_events.Events.Browser.Disconnected, f));
41
42
  }
@@ -49,29 +50,55 @@ class Browser extends import_channelOwner.ChannelOwner {
49
50
  return await this._innerNewContext(options, false);
50
51
  }
51
52
  async _newContextForReuse(options = {}) {
52
- return await this._wrapApiCall(async () => {
53
- for (const context of this._contexts) {
54
- await this._browserType._willCloseContext(context);
55
- for (const page of context.pages())
56
- page._onClose();
57
- context._onClose();
58
- }
59
- return await this._innerNewContext(options, true);
60
- }, true);
61
- }
62
- async _stopPendingOperations(reason) {
63
- return await this._wrapApiCall(async () => {
64
- await this._channel.stopPendingOperations({ reason });
65
- }, true);
53
+ return await this._innerNewContext(options, true);
54
+ }
55
+ async _disconnectFromReusedContext(reason) {
56
+ const context = [...this._contexts].find((context2) => context2._forReuse);
57
+ if (!context)
58
+ return;
59
+ await this._instrumentation.runBeforeCloseBrowserContext(context);
60
+ for (const page of context.pages())
61
+ page._onClose();
62
+ context._onClose();
63
+ await this._channel.disconnectFromReusedContext({ reason });
66
64
  }
67
65
  async _innerNewContext(options = {}, forReuse) {
68
- options = { ...this._browserType._playwright._defaultContextOptions, ...options };
66
+ options = this._browserType._playwright.selectors._withSelectorOptions({
67
+ ...this._browserType._playwright._defaultContextOptions,
68
+ ...options
69
+ });
69
70
  const contextOptions = await (0, import_browserContext.prepareBrowserContextParams)(this._platform, options);
70
71
  const response = forReuse ? await this._channel.newContextForReuse(contextOptions) : await this._channel.newContext(contextOptions);
71
72
  const context = import_browserContext.BrowserContext.from(response.context);
72
- await this._browserType._didCreateContext(context, contextOptions, this._options, options.logger || this._logger);
73
+ if (forReuse)
74
+ context._forReuse = true;
75
+ if (options.logger)
76
+ context._logger = options.logger;
77
+ await context._initializeHarFromOptions(options.recordHar);
78
+ await this._instrumentation.runAfterCreateBrowserContext(context);
73
79
  return context;
74
80
  }
81
+ _connectToBrowserType(browserType, browserOptions, logger) {
82
+ this._browserType = browserType;
83
+ this._options = browserOptions;
84
+ this._logger = logger;
85
+ for (const context of this._contexts)
86
+ this._setupBrowserContext(context);
87
+ }
88
+ _didCreateContext(context) {
89
+ context._browser = this;
90
+ this._contexts.add(context);
91
+ if (this._browserType)
92
+ this._setupBrowserContext(context);
93
+ }
94
+ _setupBrowserContext(context) {
95
+ context._logger = this._logger;
96
+ context.tracing._tracesDir = this._options.tracesDir;
97
+ this._browserType._contexts.add(context);
98
+ this._browserType._playwright.selectors._contextsForSelectors.add(context);
99
+ context.setDefaultTimeout(this._browserType._playwright._defaultContextTimeout);
100
+ context.setDefaultNavigationTimeout(this._browserType._playwright._defaultContextNavigationTimeout);
101
+ }
75
102
  contexts() {
76
103
  return [...this._contexts];
77
104
  }
@@ -85,7 +112,7 @@ class Browser extends import_channelOwner.ChannelOwner {
85
112
  page._ownedContext = context;
86
113
  context._ownerPage = page;
87
114
  return page;
88
- });
115
+ }, { title: "Create page" });
89
116
  }
90
117
  isConnected() {
91
118
  return this._isConnected;
@@ -93,6 +120,16 @@ class Browser extends import_channelOwner.ChannelOwner {
93
120
  async newBrowserCDPSession() {
94
121
  return import_cdpSession.CDPSession.from((await this._channel.newBrowserCDPSession()).session);
95
122
  }
123
+ async _launchServer(options = {}) {
124
+ const serverLauncher = this._browserType._serverLauncher;
125
+ const browserImpl = this._connection.toImpl?.(this);
126
+ if (!serverLauncher || !browserImpl)
127
+ throw new Error("Launching server is not supported");
128
+ return await serverLauncher.launchServerOnExistingBrowser(browserImpl, {
129
+ _sharedBrowser: true,
130
+ ...options
131
+ });
132
+ }
96
133
  async startTracing(page, options = {}) {
97
134
  this._path = options.path;
98
135
  await this._channel.startTracing({ ...options, page: page ? page._channel : void 0 });