rebrowser-playwright-core 1.47.100 → 1.49.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 (156) hide show
  1. package/README.md +1 -1
  2. package/ThirdPartyNotices.txt +70 -384
  3. package/bin/reinstall_chrome_beta_linux.sh +10 -8
  4. package/bin/reinstall_chrome_stable_linux.sh +10 -8
  5. package/bin/reinstall_msedge_beta_linux.sh +11 -9
  6. package/bin/reinstall_msedge_dev_linux.sh +11 -9
  7. package/bin/reinstall_msedge_stable_linux.sh +11 -9
  8. package/browsers.json +24 -12
  9. package/lib/cli/program.js +49 -19
  10. package/lib/client/api.js +6 -0
  11. package/lib/client/browserContext.js +20 -2
  12. package/lib/client/channelOwner.js +6 -2
  13. package/lib/client/connection.js +3 -0
  14. package/lib/client/fetch.js +16 -21
  15. package/lib/client/jsHandle.js +0 -8
  16. package/lib/client/localUtils.js +1 -0
  17. package/lib/client/locator.js +7 -0
  18. package/lib/client/network.js +180 -17
  19. package/lib/client/page.js +25 -2
  20. package/lib/client/playwright.js +6 -3
  21. package/lib/client/tracing.js +29 -20
  22. package/lib/client/waiter.js +15 -11
  23. package/lib/generated/consoleApiSource.js +1 -1
  24. package/lib/generated/injectedScriptSource.js +1 -1
  25. package/lib/generated/pollingRecorderSource.js +7 -0
  26. package/lib/generated/webSocketMockSource.js +7 -0
  27. package/lib/protocol/validator.js +103 -17
  28. package/lib/server/ariaSnapshot.js +33 -0
  29. package/lib/server/bidi/bidiBrowser.js +23 -8
  30. package/lib/server/bidi/bidiChromium.js +124 -0
  31. package/lib/server/bidi/bidiConnection.js +1 -3
  32. package/lib/server/bidi/bidiExecutionContext.js +0 -6
  33. package/lib/server/bidi/bidiFirefox.js +15 -21
  34. package/lib/server/bidi/bidiInput.js +16 -32
  35. package/lib/server/bidi/bidiNetworkManager.js +39 -5
  36. package/lib/server/bidi/bidiOverCdp.js +103 -0
  37. package/lib/server/bidi/bidiPage.js +98 -25
  38. package/lib/server/bidi/bidiPdf.js +140 -0
  39. package/lib/server/bidi/third_party/firefoxPrefs.js +221 -0
  40. package/lib/server/browser.js +13 -2
  41. package/lib/server/browserContext.js +6 -23
  42. package/lib/server/browserType.js +43 -12
  43. package/lib/server/chromium/chromium.js +9 -17
  44. package/lib/server/chromium/chromiumSwitches.js +3 -1
  45. package/lib/server/chromium/crBrowser.js +4 -3
  46. package/lib/server/chromium/crConnection.js +153 -0
  47. package/lib/server/chromium/crExecutionContext.js +0 -20
  48. package/lib/server/chromium/crPage.js +13 -7
  49. package/lib/server/chromium/videoRecorder.js +1 -1
  50. package/lib/server/codegen/csharp.js +12 -17
  51. package/lib/server/codegen/java.js +5 -8
  52. package/lib/server/codegen/javascript.js +29 -7
  53. package/lib/server/codegen/language.js +14 -2
  54. package/lib/server/codegen/python.js +13 -17
  55. package/lib/server/cookieStore.js +73 -0
  56. package/lib/server/debugController.js +10 -7
  57. package/lib/server/deviceDescriptorsSource.json +127 -127
  58. package/lib/server/dialog.js +1 -0
  59. package/lib/server/dispatchers/androidDispatcher.js +13 -2
  60. package/lib/server/dispatchers/browserContextDispatcher.js +19 -2
  61. package/lib/server/dispatchers/debugControllerDispatcher.js +1 -1
  62. package/lib/server/dispatchers/dispatcher.js +1 -1
  63. package/lib/server/dispatchers/frameDispatcher.js +8 -1
  64. package/lib/server/dispatchers/jsHandleDispatcher.js +0 -5
  65. package/lib/server/dispatchers/pageDispatcher.js +9 -0
  66. package/lib/server/dispatchers/playwrightDispatcher.js +2 -1
  67. package/lib/server/dispatchers/tracingDispatcher.js +10 -0
  68. package/lib/server/dispatchers/webSocketRouteDispatcher.js +189 -0
  69. package/lib/server/dom.js +79 -36
  70. package/lib/server/download.js +9 -2
  71. package/lib/server/fetch.js +105 -96
  72. package/lib/server/firefox/ffBrowser.js +6 -4
  73. package/lib/server/firefox/ffExecutionContext.js +0 -15
  74. package/lib/server/firefox/ffNetworkManager.js +1 -1
  75. package/lib/server/firefox/ffPage.js +6 -3
  76. package/lib/server/firefox/firefox.js +2 -13
  77. package/lib/server/frameSelectors.js +1 -1
  78. package/lib/server/frames.js +68 -67
  79. package/lib/server/har/harTracer.js +11 -0
  80. package/lib/server/index.js +0 -6
  81. package/lib/server/input.js +0 -1
  82. package/lib/server/javascript.js +0 -13
  83. package/lib/server/page.js +53 -9
  84. package/lib/server/playwright.js +5 -2
  85. package/lib/server/progress.js +0 -3
  86. package/lib/server/recorder/contextRecorder.js +33 -50
  87. package/lib/server/recorder/recorderApp.js +22 -25
  88. package/lib/server/recorder/recorderCollection.js +68 -79
  89. package/lib/server/recorder/recorderInTraceViewer.js +144 -0
  90. package/lib/server/recorder/recorderRunner.js +75 -97
  91. package/lib/server/recorder/recorderUtils.js +48 -6
  92. package/lib/server/recorder.js +87 -47
  93. package/lib/server/registry/index.js +154 -26
  94. package/lib/server/registry/nativeDeps.js +6 -3
  95. package/lib/server/socksClientCertificatesInterceptor.js +15 -3
  96. package/lib/server/trace/recorder/snapshotter.js +2 -12
  97. package/lib/server/trace/recorder/snapshotterInjected.js +21 -3
  98. package/lib/server/trace/recorder/tracing.js +127 -17
  99. package/lib/server/trace/test/inMemorySnapshotter.js +4 -4
  100. package/lib/server/trace/viewer/traceViewer.js +4 -6
  101. package/lib/server/webkit/webkit.js +1 -1
  102. package/lib/server/webkit/wkBrowser.js +8 -7
  103. package/lib/server/webkit/wkExecutionContext.js +0 -16
  104. package/lib/server/webkit/wkPage.js +11 -4
  105. package/lib/utils/comparators.js +12 -30
  106. package/lib/utils/crypto.js +1 -4
  107. package/lib/utils/happy-eyeballs.js +13 -0
  108. package/lib/utils/hostPlatform.js +8 -2
  109. package/lib/utils/httpServer.js +1 -0
  110. package/lib/utils/isomorphic/ariaSnapshot.js +267 -0
  111. package/lib/utils/isomorphic/locatorGenerators.js +30 -21
  112. package/lib/utils/isomorphic/locatorParser.js +2 -2
  113. package/lib/utils/isomorphic/recorderUtils.js +227 -0
  114. package/lib/utils/isomorphic/stringUtils.js +30 -0
  115. package/lib/utils/isomorphic/urlMatch.js +5 -1
  116. package/lib/utils/network.js +1 -1
  117. package/lib/utils/sequence.js +64 -0
  118. package/lib/utils/stackTrace.js +16 -3
  119. package/lib/utils/zones.js +32 -23
  120. package/lib/utilsBundle.js +4 -5
  121. package/lib/utilsBundleImpl/index.js +190 -33
  122. package/lib/vite/htmlReport/index.html +19 -16
  123. package/lib/vite/recorder/assets/codeMirrorModule-AFvV6hAs.js +24 -0
  124. package/lib/vite/recorder/assets/index-_cTWgVuJ.js +184 -0
  125. package/lib/vite/recorder/assets/{index-B-MT5gKo.css → index-iA1aAGZg.css} +1 -1
  126. package/lib/vite/recorder/index.html +2 -2
  127. package/lib/vite/traceViewer/assets/codeMirrorModule-KatbITLF.js +24 -0
  128. package/lib/vite/traceViewer/assets/inspectorTab-DdpLd2bb.js +68 -0
  129. package/lib/vite/traceViewer/assets/workbench-CdYbzWFD.js +9 -0
  130. package/lib/vite/traceViewer/embedded.6m3UZh7r.js +2 -0
  131. package/lib/vite/traceViewer/embedded.html +5 -3
  132. package/lib/vite/traceViewer/index.WUV-8boJ.js +2 -0
  133. package/lib/vite/traceViewer/index.html +24 -5
  134. package/lib/vite/traceViewer/inspectorTab.DEOUW62d.css +1 -0
  135. package/lib/vite/traceViewer/recorder.B_SY1GJM.css +0 -0
  136. package/lib/vite/traceViewer/recorder.OT2tVHgn.js +2 -0
  137. package/lib/vite/traceViewer/recorder.html +17 -0
  138. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  139. package/lib/vite/traceViewer/uiMode.BZBTyvGn.js +5 -0
  140. package/lib/vite/traceViewer/uiMode.html +6 -4
  141. package/lib/vite/traceViewer/{uiMode.D3cNFP6u.css → uiMode.voC1ZiOQ.css} +1 -1
  142. package/lib/vite/traceViewer/workbench.C-zR9ysA.css +1 -0
  143. package/package.json +1 -1
  144. package/types/protocol.d.ts +135 -16
  145. package/types/types.d.ts +2149 -965
  146. package/lib/generated/recorderSource.js +0 -7
  147. package/lib/third_party/diff_match_patch.js +0 -2222
  148. package/lib/vite/recorder/assets/codeMirrorModule-aW6Vz3gf.js +0 -24
  149. package/lib/vite/recorder/assets/index-DCpXOVIh.js +0 -47
  150. package/lib/vite/traceViewer/assets/codeMirrorModule-eFKCUIu2.js +0 -24
  151. package/lib/vite/traceViewer/assets/workbench-D0cirtfA.js +0 -72
  152. package/lib/vite/traceViewer/embedded.BkuvsLJp.js +0 -2
  153. package/lib/vite/traceViewer/index.C968kAiC.js +0 -2
  154. package/lib/vite/traceViewer/uiMode.BkFnr4V0.js +0 -10
  155. package/lib/vite/traceViewer/workbench.DjbIuxix.css +0 -1
  156. /package/lib/server/recorder/{recorderActions.js → recorderFrontend.js} +0 -0
@@ -8,15 +8,17 @@ if [[ $(arch) == "aarch64" ]]; then
8
8
  exit 1
9
9
  fi
10
10
 
11
- if [[ ! -f "/etc/os-release" ]]; then
12
- echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
13
- exit 1
14
- fi
15
-
16
- ID=$(bash -c 'source /etc/os-release && echo $ID')
17
- if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
18
- echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
19
- exit 1
11
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
12
+ if [[ ! -f "/etc/os-release" ]]; then
13
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
14
+ exit 1
15
+ fi
16
+
17
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
18
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
19
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
20
+ exit 1
21
+ fi
20
22
  fi
21
23
 
22
24
  # 1. make sure to remove old dev if any.
@@ -8,15 +8,17 @@ if [[ $(arch) == "aarch64" ]]; then
8
8
  exit 1
9
9
  fi
10
10
 
11
- if [[ ! -f "/etc/os-release" ]]; then
12
- echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
13
- exit 1
14
- fi
15
-
16
- ID=$(bash -c 'source /etc/os-release && echo $ID')
17
- if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
18
- echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
19
- exit 1
11
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
12
+ if [[ ! -f "/etc/os-release" ]]; then
13
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
14
+ exit 1
15
+ fi
16
+
17
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
18
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
19
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
20
+ exit 1
21
+ fi
20
22
  fi
21
23
 
22
24
  # 1. make sure to remove old stable if any.
package/browsers.json CHANGED
@@ -3,31 +3,37 @@
3
3
  "browsers": [
4
4
  {
5
5
  "name": "chromium",
6
- "revision": "1134",
6
+ "revision": "1148",
7
7
  "installByDefault": true,
8
- "browserVersion": "129.0.6668.29"
8
+ "browserVersion": "131.0.6778.33"
9
+ },
10
+ {
11
+ "name": "chromium-headless-shell",
12
+ "revision": "1148",
13
+ "installByDefault": true,
14
+ "browserVersion": "131.0.6778.33"
9
15
  },
10
16
  {
11
17
  "name": "chromium-tip-of-tree",
12
- "revision": "1256",
18
+ "revision": "1277",
13
19
  "installByDefault": false,
14
- "browserVersion": "130.0.6695.0"
20
+ "browserVersion": "132.0.6834.0"
15
21
  },
16
22
  {
17
23
  "name": "firefox",
18
- "revision": "1463",
24
+ "revision": "1466",
19
25
  "installByDefault": true,
20
- "browserVersion": "130.0"
26
+ "browserVersion": "132.0"
21
27
  },
22
28
  {
23
29
  "name": "firefox-beta",
24
- "revision": "1462",
30
+ "revision": "1465",
25
31
  "installByDefault": false,
26
- "browserVersion": "130.0b2"
32
+ "browserVersion": "132.0b8"
27
33
  },
28
34
  {
29
35
  "name": "webkit",
30
- "revision": "2070",
36
+ "revision": "2104",
31
37
  "installByDefault": true,
32
38
  "revisionOverrides": {
33
39
  "mac10.14": "1446",
@@ -35,14 +41,20 @@
35
41
  "mac11": "1816",
36
42
  "mac11-arm64": "1816",
37
43
  "mac12": "2009",
38
- "mac12-arm64": "2009"
44
+ "mac12-arm64": "2009",
45
+ "ubuntu20.04-x64": "2092",
46
+ "ubuntu20.04-arm64": "2092"
39
47
  },
40
- "browserVersion": "18.0"
48
+ "browserVersion": "18.2"
41
49
  },
42
50
  {
43
51
  "name": "ffmpeg",
44
52
  "revision": "1010",
45
- "installByDefault": true
53
+ "installByDefault": true,
54
+ "revisionOverrides": {
55
+ "mac12": "1010",
56
+ "mac12-arm64": "1010"
57
+ }
46
58
  },
47
59
  {
48
60
  "name": "android",
@@ -82,23 +82,41 @@ Examples:
82
82
  function suggestedBrowsersToInstall() {
83
83
  return _server.registry.executables().filter(e => e.installType !== 'none' && e.type !== 'tool').map(e => e.name).join(', ');
84
84
  }
85
- function checkBrowsersToInstall(args) {
85
+ function defaultBrowsersToInstall(options) {
86
+ let executables = _server.registry.defaultExecutables();
87
+ if (options.noShell) executables = executables.filter(e => e.name !== 'chromium-headless-shell');
88
+ if (options.onlyShell) executables = executables.filter(e => e.name !== 'chromium');
89
+ return executables;
90
+ }
91
+ function checkBrowsersToInstall(args, options) {
92
+ if (options.noShell && options.onlyShell) throw new Error(`Only one of --no-shell and --only-shell can be specified`);
86
93
  const faultyArguments = [];
87
94
  const executables = [];
88
- for (const arg of args) {
95
+ const handleArgument = arg => {
89
96
  const executable = _server.registry.findExecutable(arg);
90
97
  if (!executable || executable.installType === 'none') faultyArguments.push(arg);else executables.push(executable);
98
+ if ((executable === null || executable === void 0 ? void 0 : executable.browserName) === 'chromium') executables.push(_server.registry.findExecutable('ffmpeg'));
99
+ };
100
+ for (const arg of args) {
101
+ if (arg === 'chromium') {
102
+ if (!options.onlyShell) handleArgument('chromium');
103
+ if (!options.noShell) handleArgument('chromium-headless-shell');
104
+ } else {
105
+ handleArgument(arg);
106
+ }
91
107
  }
92
108
  if (faultyArguments.length) throw new Error(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${suggestedBrowsersToInstall()}`);
93
109
  return executables;
94
110
  }
95
- _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').action(async function (args, options) {
111
+ _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) {
112
+ // For '--no-shell' option, commander sets `shell: false` instead.
113
+ if (options.shell === false) options.noShell = true;
96
114
  if ((0, _utils.isLikelyNpxGlobal)()) {
97
115
  console.error((0, _utils.wrapInASCIIBox)([`WARNING: It looks like you are running 'npx playwright install' without first`, `installing your project's dependencies.`, ``, `To avoid unexpected behavior, please install your dependencies first, and`, `then run Playwright's install command:`, ``, ` npm install`, ` npx playwright install`, ``, `If your project does not yet depend on Playwright, first install the`, `applicable npm package (most commonly @playwright/test), and`, `then run Playwright's install command to download the browsers:`, ``, ` npm install @playwright/test`, ` npx playwright install`, ``].join('\n'), 1));
98
116
  }
99
117
  try {
100
118
  const hasNoArguments = !args.length;
101
- const executables = hasNoArguments ? _server.registry.defaultExecutables() : checkBrowsersToInstall(args);
119
+ const executables = hasNoArguments ? defaultBrowsersToInstall(options) : checkBrowsersToInstall(args, options);
102
120
  if (options.withDeps) await _server.registry.installDeps(executables, !!options.dryRun);
103
121
  if (options.dryRun) {
104
122
  for (const executable of executables) {
@@ -146,7 +164,7 @@ _utilsBundle.program.command('uninstall').description('Removes browsers used by
146
164
  });
147
165
  _utilsBundle.program.command('install-deps [browser...]').description('install dependencies necessary to run browsers (will ask for sudo permissions)').option('--dry-run', 'Do not execute installation commands, only print them').action(async function (args, options) {
148
166
  try {
149
- if (!args.length) await _server.registry.installDeps(_server.registry.defaultExecutables(), !!options.dryRun);else await _server.registry.installDeps(checkBrowsersToInstall(args), !!options.dryRun);
167
+ if (!args.length) await _server.registry.installDeps(defaultBrowsersToInstall({}), !!options.dryRun);else await _server.registry.installDeps(checkBrowsersToInstall(args, {}), !!options.dryRun);
150
168
  } catch (e) {
151
169
  console.log(`Failed to install browser dependencies\n${e}`);
152
170
  (0, _utils.gracefullyProcessExitDoNotHang)(1);
@@ -238,13 +256,10 @@ _utilsBundle.program.command('show-trace [trace...]').option('-b, --browser <bro
238
256
  Examples:
239
257
 
240
258
  $ show-trace https://example.com/trace.zip`);
241
- async function launchContext(options, headless, executablePath) {
259
+ async function launchContext(options, extraOptions) {
242
260
  validateOptions(options);
243
261
  const browserType = lookupBrowserType(options);
244
- const launchOptions = {
245
- headless,
246
- executablePath
247
- };
262
+ const launchOptions = extraOptions;
248
263
  if (options.channel) launchOptions.channel = options.channel;
249
264
  launchOptions.handleSIGINT = false;
250
265
  const contextOptions =
@@ -256,7 +271,7 @@ async function launchContext(options, headless, executablePath) {
256
271
  // In headful mode, use host device scale factor for things to look nice.
257
272
  // In headless, keep things the way it works in Playwright by default.
258
273
  // Assume high-dpi on MacOS. TODO: this is not perfect.
259
- if (!headless) contextOptions.deviceScaleFactor = _os.default.platform() === 'darwin' ? 2 : 1;
274
+ if (!extraOptions.headless) contextOptions.deviceScaleFactor = _os.default.platform() === 'darwin' ? 2 : 1;
260
275
 
261
276
  // Work around the WebKit GTK scrolling issue.
262
277
  if (browserType.name() === 'webkit' && process.platform === 'linux') {
@@ -281,7 +296,7 @@ async function launchContext(options, headless, executablePath) {
281
296
  process.stdout.write(text);
282
297
  process.stdout.write('\n-------------8<-------------\n');
283
298
  const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
284
- if (autoExitCondition && text.includes(autoExitCondition)) Promise.all(context.pages().map(async p => p.close()));
299
+ if (autoExitCondition && text.includes(autoExitCondition)) closeBrowser();
285
300
  };
286
301
  // Make sure we exit abnormally when browser crashes.
287
302
  const logs = [];
@@ -383,7 +398,7 @@ async function launchContext(options, headless, executablePath) {
383
398
  const hasPage = browser.contexts().some(context => context.pages().length > 0);
384
399
  if (hasPage) return;
385
400
  // Avoid the error when the last page is closed because the browser has been closed.
386
- closeBrowser().catch(e => null);
401
+ closeBrowser().catch(() => {});
387
402
  });
388
403
  });
389
404
  process.on('SIGINT', async () => {
@@ -431,13 +446,17 @@ async function open(options, url, language) {
431
446
  context,
432
447
  launchOptions,
433
448
  contextOptions
434
- } = await launchContext(options, !!process.env.PWTEST_CLI_HEADLESS, process.env.PWTEST_CLI_EXECUTABLE_PATH);
449
+ } = await launchContext(options, {
450
+ headless: !!process.env.PWTEST_CLI_HEADLESS,
451
+ executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH
452
+ });
435
453
  await context._enableRecorder({
436
454
  language,
437
455
  launchOptions,
438
456
  contextOptions,
439
457
  device: options.device,
440
- saveStorage: options.saveStorage
458
+ saveStorage: options.saveStorage,
459
+ handleSIGINT: false
441
460
  });
442
461
  await openPage(context, url);
443
462
  }
@@ -447,11 +466,16 @@ async function codegen(options, url) {
447
466
  output: outputFile,
448
467
  testIdAttribute: testIdAttributeName
449
468
  } = options;
469
+ const tracesDir = _path.default.join(_os.default.tmpdir(), `playwright-recorder-trace-${Date.now()}`);
450
470
  const {
451
471
  context,
452
472
  launchOptions,
453
473
  contextOptions
454
- } = await launchContext(options, !!process.env.PWTEST_CLI_HEADLESS, process.env.PWTEST_CLI_EXECUTABLE_PATH);
474
+ } = await launchContext(options, {
475
+ headless: !!process.env.PWTEST_CLI_HEADLESS,
476
+ executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH,
477
+ tracesDir
478
+ });
455
479
  _utilsBundle.dotenv.config({
456
480
  path: 'playwright.env'
457
481
  });
@@ -462,8 +486,10 @@ async function codegen(options, url) {
462
486
  device: options.device,
463
487
  saveStorage: options.saveStorage,
464
488
  mode: 'recording',
489
+ codegenMode: process.env.PW_RECORDER_IS_TRACE_VIEWER ? 'trace-events' : 'actions',
465
490
  testIdAttributeName,
466
- outputFile: outputFile ? _path.default.resolve(outputFile) : undefined
491
+ outputFile: outputFile ? _path.default.resolve(outputFile) : undefined,
492
+ handleSIGINT: false
467
493
  });
468
494
  await openPage(context, url);
469
495
  }
@@ -480,7 +506,9 @@ async function waitForPage(page, captureOptions) {
480
506
  async function screenshot(options, captureOptions, url, path) {
481
507
  const {
482
508
  context
483
- } = await launchContext(options, true);
509
+ } = await launchContext(options, {
510
+ headless: true
511
+ });
484
512
  console.log('Navigating to ' + url);
485
513
  const page = await openPage(context, url);
486
514
  await waitForPage(page, captureOptions);
@@ -499,7 +527,9 @@ async function pdf(options, captureOptions, url, path) {
499
527
  } = await launchContext({
500
528
  ...options,
501
529
  browser: 'chromium'
502
- }, true);
530
+ }, {
531
+ headless: true
532
+ });
503
533
  console.log('Navigating to ' + url);
504
534
  const page = await openPage(context, url);
505
535
  await waitForPage(page, captureOptions);
package/lib/client/api.js CHANGED
@@ -243,6 +243,12 @@ Object.defineProperty(exports, "WebSocket", {
243
243
  return _network.WebSocket;
244
244
  }
245
245
  });
246
+ Object.defineProperty(exports, "WebSocketRoute", {
247
+ enumerable: true,
248
+ get: function () {
249
+ return _network.WebSocketRoute;
250
+ }
251
+ });
246
252
  Object.defineProperty(exports, "Worker", {
247
253
  enumerable: true,
248
254
  get: function () {
@@ -63,6 +63,7 @@ class BrowserContext extends _channelOwner.ChannelOwner {
63
63
  super(parent, type, guid, initializer);
64
64
  this._pages = new Set();
65
65
  this._routes = [];
66
+ this._webSocketRoutes = [];
66
67
  this._browser = null;
67
68
  this._browserType = void 0;
68
69
  this._bindings = new Map();
@@ -96,6 +97,9 @@ class BrowserContext extends _channelOwner.ChannelOwner {
96
97
  this._channel.on('route', ({
97
98
  route
98
99
  }) => this._onRoute(network.Route.from(route)));
100
+ this._channel.on('webSocketRoute', ({
101
+ webSocketRoute
102
+ }) => this._onWebSocketRoute(network.WebSocketRoute.from(webSocketRoute)));
99
103
  this._channel.on('backgroundPage', ({
100
104
  page
101
105
  }) => {
@@ -215,7 +219,11 @@ class BrowserContext extends _channelOwner.ChannelOwner {
215
219
  }
216
220
  // If the page is closed or unrouteAll() was called without waiting and interception disabled,
217
221
  // the method will throw an error - silence it.
218
- await route._innerContinue(true).catch(() => {});
222
+ await route._innerContinue(true /* isFallback */).catch(() => {});
223
+ }
224
+ async _onWebSocketRoute(webSocketRoute) {
225
+ const routeHandler = this._webSocketRoutes.find(route => route.matches(webSocketRoute.url()));
226
+ if (routeHandler) await routeHandler.handle(webSocketRoute);else webSocketRoute.connectToServer();
219
227
  }
220
228
  async _onBinding(bindingCall) {
221
229
  const func = this._bindings.get(bindingCall._initializer.name);
@@ -327,6 +335,10 @@ class BrowserContext extends _channelOwner.ChannelOwner {
327
335
  this._routes.unshift(new network.RouteHandler(this._options.baseURL, url, handler, options.times));
328
336
  await this._updateInterceptionPatterns();
329
337
  }
338
+ async routeWebSocket(url, handler) {
339
+ this._webSocketRoutes.unshift(new network.WebSocketRouteHandler(this._options.baseURL, url, handler));
340
+ await this._updateWebSocketInterceptionPatterns();
341
+ }
330
342
  async _recordIntoHAR(har, page, options = {}) {
331
343
  var _options$updateConten, _options$updateMode, _options$updateConten2;
332
344
  const {
@@ -385,6 +397,12 @@ class BrowserContext extends _channelOwner.ChannelOwner {
385
397
  patterns
386
398
  });
387
399
  }
400
+ async _updateWebSocketInterceptionPatterns() {
401
+ const patterns = network.WebSocketRouteHandler.prepareInterceptionPatterns(this._webSocketRoutes);
402
+ await this._channel.setWebSocketInterceptionPatterns({
403
+ patterns
404
+ });
405
+ }
388
406
  _effectiveCloseReason() {
389
407
  var _this$_browser3;
390
408
  return this._closeReason || ((_this$_browser3 = this._browser) === null || _this$_browser3 === void 0 ? void 0 : _this$_browser3._closeReason);
@@ -470,7 +488,7 @@ class BrowserContext extends _channelOwner.ChannelOwner {
470
488
  await this._closedPromise;
471
489
  }
472
490
  async _enableRecorder(params) {
473
- await this._channel.recorderSupplementEnable(params);
491
+ await this._channel.enableRecorder(params);
474
492
  }
475
493
  }
476
494
  exports.BrowserContext = BrowserContext;
@@ -39,6 +39,7 @@ class ChannelOwner extends _eventEmitter.EventEmitter {
39
39
  this._logger = void 0;
40
40
  this._instrumentation = void 0;
41
41
  this._eventToSubscriptionMapping = new Map();
42
+ this._isInternalType = false;
42
43
  this._wasCollected = false;
43
44
  this.setMaxListeners(0);
44
45
  this._connection = parent instanceof ChannelOwner ? parent._connection : parent;
@@ -54,6 +55,9 @@ class ChannelOwner extends _eventEmitter.EventEmitter {
54
55
  this._channel = this._createChannel(new _eventEmitter.EventEmitter());
55
56
  this._initializer = initializer;
56
57
  }
58
+ markAsInternalType() {
59
+ this._isInternalType = true;
60
+ }
57
61
  _setEventToSubscriptionMapping(mapping) {
58
62
  this._eventToSubscriptionMapping = mapping;
59
63
  }
@@ -156,14 +160,14 @@ class ChannelOwner extends _eventEmitter.EventEmitter {
156
160
  channel._object = this;
157
161
  return channel;
158
162
  }
159
- async _wrapApiCall(func, isInternal = false) {
163
+ async _wrapApiCall(func, isInternal) {
160
164
  const logger = this._logger;
161
165
  const apiZone = _zones.zones.zoneData('apiZone');
162
166
  if (apiZone) return await func(apiZone);
163
167
  const stackTrace = (0, _stackTrace.captureLibraryStackTrace)();
164
168
  let apiName = stackTrace.apiName;
165
169
  const frames = stackTrace.frames;
166
- isInternal = isInternal || this._type === 'LocalUtils';
170
+ if (isInternal === undefined) isInternal = this._isInternalType;
167
171
  if (isInternal) apiName = undefined;
168
172
 
169
173
  // Enclosing zone could have provided the apiName and wallTime.
@@ -315,6 +315,9 @@ class Connection extends _events.EventEmitter {
315
315
  case 'WebSocket':
316
316
  result = new _network.WebSocket(parent, type, guid, initializer);
317
317
  break;
318
+ case 'WebSocketRoute':
319
+ result = new _network.WebSocketRoute(parent, type, guid, initializer);
320
+ break;
318
321
  case 'Worker':
319
322
  result = new _worker.Worker(parent, type, guid, initializer);
320
323
  break;
@@ -147,8 +147,9 @@ class APIRequestContext extends _channelOwner.ChannelOwner {
147
147
  (0, _utils.assert)(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' must be greater than or equal to '0'`);
148
148
  (0, _utils.assert)(options.maxRetries === undefined || options.maxRetries >= 0, `'maxRetries' must be greater than or equal to '0'`);
149
149
  const url = options.url !== undefined ? options.url : options.request.url();
150
- const params = mapParamsToArray(options.params);
151
150
  const method = options.method || ((_options$request = options.request) === null || _options$request === void 0 ? void 0 : _options$request.method());
151
+ let encodedParams = undefined;
152
+ if (typeof options.params === 'string') encodedParams = options.params;else if (options.params instanceof URLSearchParams) encodedParams = options.params.toString();
152
153
  // Cannot call allHeaders() here as the request may be paused inside route handler.
153
154
  const headersObj = options.headers || ((_options$request2 = options.request) === null || _options$request2 === void 0 ? void 0 : _options$request2.headers());
154
155
  const headers = headersObj ? (0, _utils.headersObjectToArray)(headersObj) : undefined;
@@ -167,7 +168,18 @@ class APIRequestContext extends _channelOwner.ChannelOwner {
167
168
  throw new Error(`Unexpected 'data' type`);
168
169
  }
169
170
  } else if (options.form) {
170
- formData = objectToArray(options.form);
171
+ if (globalThis.FormData && options.form instanceof FormData) {
172
+ formData = [];
173
+ for (const [name, value] of options.form.entries()) {
174
+ if (typeof value !== 'string') throw new Error(`Expected string for options.form["${name}"], found File. Please use options.multipart instead.`);
175
+ formData.push({
176
+ name,
177
+ value
178
+ });
179
+ }
180
+ } else {
181
+ formData = objectToArray(options.form);
182
+ }
171
183
  } else if (options.multipart) {
172
184
  multipartData = [];
173
185
  if (globalThis.FormData && options.multipart instanceof FormData) {
@@ -201,7 +213,8 @@ class APIRequestContext extends _channelOwner.ChannelOwner {
201
213
  };
202
214
  const result = await this._channel.fetch({
203
215
  url,
204
- params,
216
+ params: typeof options.params === 'object' ? objectToArray(options.params) : undefined,
217
+ encodedParams,
205
218
  method,
206
219
  headers,
207
220
  postData: postDataBuffer,
@@ -373,24 +386,6 @@ function objectToArray(map) {
373
386
  });
374
387
  return result;
375
388
  }
376
- function queryStringToArray(queryString) {
377
- const searchParams = new URLSearchParams(queryString);
378
- return searchParamsToArray(searchParams);
379
- }
380
- function searchParamsToArray(searchParams) {
381
- if (searchParams.size === 0) return undefined;
382
- const result = [];
383
- for (const [name, value] of searchParams.entries()) result.push({
384
- name,
385
- value
386
- });
387
- return result;
388
- }
389
- function mapParamsToArray(params) {
390
- if (params instanceof URLSearchParams) return searchParamsToArray(params);
391
- if (typeof params === 'string') return queryStringToArray(params);
392
- return objectToArray(params);
393
- }
394
389
  function isFilePayload(value) {
395
390
  return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer'];
396
391
  }
@@ -86,14 +86,6 @@ class JSHandle extends _channelOwner.ChannelOwner {
86
86
  throw e;
87
87
  }
88
88
  }
89
- async _objectCount() {
90
- return await this._wrapApiCall(async () => {
91
- const {
92
- count
93
- } = await this._channel.objectCount();
94
- return count;
95
- });
96
- }
97
89
  toString() {
98
90
  return this._preview;
99
91
  }
@@ -25,6 +25,7 @@ class LocalUtils extends _channelOwner.ChannelOwner {
25
25
  constructor(parent, type, guid, initializer) {
26
26
  super(parent, type, guid, initializer);
27
27
  this.devices = void 0;
28
+ this.markAsInternalType();
28
29
  this.devices = {};
29
30
  for (const {
30
31
  name,
@@ -291,6 +291,13 @@ class Locator {
291
291
  timeout
292
292
  }), options.timeout);
293
293
  }
294
+ async ariaSnapshot(options) {
295
+ const result = await this._frame._channel.ariaSnapshot({
296
+ ...options,
297
+ selector: this._selector
298
+ });
299
+ return result.snapshot;
300
+ }
294
301
  async scrollIntoViewIfNeeded(options = {}) {
295
302
  return await this._withElement((h, timeout) => h.scrollIntoViewIfNeeded({
296
303
  ...options,