@checkly/playwright-core 1.47.20-alpha → 1.48.10-alpha

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 (167) hide show
  1. package/browsers.json +14 -10
  2. package/lib/checkly/escapeRegExp.js +33 -0
  3. package/lib/checkly/secretsFilter.js +23 -0
  4. package/lib/cli/program.js +22 -12
  5. package/lib/client/api.js +6 -0
  6. package/lib/client/browserContext.js +20 -2
  7. package/lib/client/channelOwner.js +5 -2
  8. package/lib/client/connection.js +3 -0
  9. package/lib/client/fetch.js +16 -3
  10. package/lib/client/jsHandle.js +0 -8
  11. package/lib/client/localUtils.js +1 -0
  12. package/lib/client/network.js +175 -17
  13. package/lib/client/page.js +21 -0
  14. package/lib/client/playwright.js +6 -3
  15. package/lib/client/tracing.js +16 -20
  16. package/lib/generated/consoleApiSource.js +1 -1
  17. package/lib/generated/injectedScriptSource.js +1 -1
  18. package/lib/generated/pollingRecorderSource.js +7 -0
  19. package/lib/generated/webSocketMockSource.js +7 -0
  20. package/lib/protocol/validator.js +79 -14
  21. package/lib/server/bidi/bidiBrowser.js +23 -8
  22. package/lib/server/bidi/bidiChromium.js +124 -0
  23. package/lib/server/bidi/bidiConnection.js +1 -1
  24. package/lib/server/bidi/bidiExecutionContext.js +0 -3
  25. package/lib/server/bidi/bidiFirefox.js +15 -21
  26. package/lib/server/bidi/bidiInput.js +16 -32
  27. package/lib/server/bidi/bidiNetworkManager.js +39 -5
  28. package/lib/server/bidi/bidiOverCdp.js +103 -0
  29. package/lib/server/bidi/bidiPage.js +98 -25
  30. package/lib/server/bidi/bidiPdf.js +140 -0
  31. package/lib/server/bidi/third_party/firefoxPrefs.js +221 -0
  32. package/lib/server/browser.js +13 -2
  33. package/lib/server/browserContext.js +6 -23
  34. package/lib/server/browserType.js +39 -11
  35. package/lib/server/chromium/chromium.js +3 -15
  36. package/lib/server/chromium/chromiumSwitches.js +3 -1
  37. package/lib/server/chromium/crBrowser.js +4 -3
  38. package/lib/server/chromium/crExecutionContext.js +0 -7
  39. package/lib/server/chromium/crPage.js +5 -2
  40. package/lib/server/chromium/videoRecorder.js +1 -1
  41. package/lib/server/codegen/csharp.js +2 -2
  42. package/lib/server/codegen/java.js +1 -1
  43. package/lib/server/codegen/javascript.js +1 -1
  44. package/lib/server/codegen/language.js +14 -2
  45. package/lib/server/codegen/python.js +2 -2
  46. package/lib/server/cookieStore.js +73 -0
  47. package/lib/server/debugController.js +2 -2
  48. package/lib/server/deviceDescriptorsSource.json +51 -51
  49. package/lib/server/dialog.js +1 -0
  50. package/lib/server/dispatchers/browserContextDispatcher.js +19 -2
  51. package/lib/server/dispatchers/jsHandleDispatcher.js +0 -5
  52. package/lib/server/dispatchers/pageDispatcher.js +9 -0
  53. package/lib/server/dispatchers/playwrightDispatcher.js +2 -1
  54. package/lib/server/dispatchers/webSocketRouteDispatcher.js +189 -0
  55. package/lib/server/download.js +9 -2
  56. package/lib/server/fetch.js +96 -99
  57. package/lib/server/firefox/ffBrowser.js +6 -4
  58. package/lib/server/firefox/ffExecutionContext.js +0 -3
  59. package/lib/server/firefox/ffPage.js +3 -0
  60. package/lib/server/firefox/firefox.js +2 -13
  61. package/lib/server/frameSelectors.js +1 -1
  62. package/lib/server/frames.js +3 -2
  63. package/lib/server/har/harTracer.js +11 -0
  64. package/lib/server/input.js +0 -1
  65. package/lib/server/javascript.js +0 -7
  66. package/lib/server/page.js +5 -1
  67. package/lib/server/playwright.js +5 -2
  68. package/lib/server/recorder/contextRecorder.js +33 -50
  69. package/lib/server/recorder/recorderActions.js +2 -1
  70. package/lib/server/recorder/recorderApp.js +15 -9
  71. package/lib/server/recorder/recorderCollection.js +68 -79
  72. package/lib/server/recorder/recorderFrontend.js +5 -0
  73. package/lib/server/recorder/recorderInTraceViewer.js +144 -0
  74. package/lib/server/recorder/recorderRunner.js +75 -97
  75. package/lib/server/recorder/recorderUtils.js +47 -6
  76. package/lib/server/recorder.js +28 -25
  77. package/lib/server/registry/index.js +85 -4
  78. package/lib/server/socksClientCertificatesInterceptor.js +15 -3
  79. package/lib/server/trace/recorder/snapshotter.js +1 -0
  80. package/lib/server/trace/recorder/snapshotterInjected.js +2 -2
  81. package/lib/server/trace/recorder/tracing.js +70 -5
  82. package/lib/server/trace/test/inMemorySnapshotter.js +1 -1
  83. package/lib/server/trace/viewer/traceViewer.js +2 -5
  84. package/lib/server/webkit/webkit.js +1 -1
  85. package/lib/server/webkit/wkBrowser.js +6 -5
  86. package/lib/server/webkit/wkExecutionContext.js +0 -3
  87. package/lib/server/webkit/wkPage.js +4 -1
  88. package/lib/utils/happy-eyeballs.js +13 -0
  89. package/lib/utils/hostPlatform.js +2 -2
  90. package/lib/utils/httpServer.js +1 -0
  91. package/lib/utils/isomorphic/locatorGenerators.js +9 -18
  92. package/lib/utils/isomorphic/locatorParser.js +2 -2
  93. package/lib/utils/isomorphic/recorderUtils.js +195 -0
  94. package/lib/vite/htmlReport/index.html +12 -12
  95. package/lib/vite/recorder/assets/codeMirrorModule-CND2fZ5Q.js +24 -0
  96. package/lib/vite/recorder/assets/{index-B-MT5gKo.css → index-BW-aOBcL.css} +1 -1
  97. package/lib/vite/recorder/assets/{index-D-5S5PPN.js → index-CEc83sSS.js} +10 -15
  98. package/lib/vite/recorder/index.html +2 -2
  99. package/lib/vite/traceViewer/assets/codeMirrorModule-BdBhzV6t.js +16443 -0
  100. package/lib/vite/traceViewer/assets/codeMirrorModule-BqcXH1AO.js +16838 -0
  101. package/lib/vite/traceViewer/assets/codeMirrorModule-Ca-1BNel.js +24 -0
  102. package/lib/vite/traceViewer/assets/codeMirrorModule-CcviAl53.js +16831 -0
  103. package/lib/vite/traceViewer/assets/codeMirrorModule-DS3v0XrQ.js +24 -0
  104. package/lib/vite/traceViewer/assets/codeMirrorModule-EhKN7Okm.js +16449 -0
  105. package/lib/vite/{recorder/assets/codeMirrorModule-C-fQ5QZD.js → traceViewer/assets/codeMirrorModule-MzSmL4X2.js} +1 -1
  106. package/lib/vite/traceViewer/assets/codeMirrorModule-U6XMqGkV.js +16437 -0
  107. package/lib/vite/traceViewer/assets/inspectorTab-BABZNwlH.js +17351 -0
  108. package/lib/vite/traceViewer/assets/inspectorTab-BPzVEZSf.js +17351 -0
  109. package/lib/vite/traceViewer/assets/inspectorTab-Bbgq0hgt.js +64 -0
  110. package/lib/vite/traceViewer/assets/inspectorTab-DhBbZz8I.js +64 -0
  111. package/lib/vite/traceViewer/assets/inspectorTab-DpvLVMq5.js +17351 -0
  112. package/lib/vite/traceViewer/assets/workbench-B13nfocr.js +9 -0
  113. package/lib/vite/traceViewer/assets/workbench-BcgGQnKb.js +1473 -0
  114. package/lib/vite/traceViewer/assets/workbench-BwodYCgl.js +19119 -0
  115. package/lib/vite/traceViewer/assets/workbench-ByyWxoT8.js +1473 -0
  116. package/lib/vite/traceViewer/assets/workbench-Crj6jzdv.js +19119 -0
  117. package/lib/vite/traceViewer/assets/workbench-DhqI6jeL.js +1473 -0
  118. package/lib/vite/traceViewer/assets/workbench-Pa1v1Ojh.js +72 -0
  119. package/lib/vite/traceViewer/assets/workbench-gtYcQBNA.js +9 -0
  120. package/lib/vite/traceViewer/assets/xtermModule-DZP0glxx.js +5982 -0
  121. package/lib/vite/traceViewer/embedded.27BGR_eD.js +105 -0
  122. package/lib/vite/traceViewer/embedded.BBZ9gQEw.js +104 -0
  123. package/lib/vite/traceViewer/embedded.CorI3dFX.js +104 -0
  124. package/lib/vite/traceViewer/embedded.D4lqGydT.js +2 -0
  125. package/lib/vite/traceViewer/embedded.DTjd2aiy.js +105 -0
  126. package/lib/vite/traceViewer/embedded.DbzY7Q8w.js +2 -0
  127. package/lib/vite/traceViewer/embedded.SsjKHrxC.js +105 -0
  128. package/lib/vite/traceViewer/embedded.f-PLGsBT.js +2 -0
  129. package/lib/vite/traceViewer/embedded.html +5 -3
  130. package/lib/vite/traceViewer/index.B7aiTMfZ.js +2 -0
  131. package/lib/vite/traceViewer/index.BSak5QT9.js +2 -0
  132. package/lib/vite/traceViewer/index.BrT2kfuc.js +2 -0
  133. package/lib/vite/traceViewer/index.DkRbtWVo.js +195 -0
  134. package/lib/vite/traceViewer/index.DsjmhbB6.js +195 -0
  135. package/lib/vite/traceViewer/index.Dz3icWJV.js +196 -0
  136. package/lib/vite/traceViewer/index.PqcsvBxQ.js +196 -0
  137. package/lib/vite/traceViewer/index.html +5 -3
  138. package/lib/vite/traceViewer/index.yxAwzeWG.js +196 -0
  139. package/lib/vite/traceViewer/inspectorTab.DGJWXOSd.css +3145 -0
  140. package/lib/vite/traceViewer/inspectorTab.DLjBDrQR.css +1 -0
  141. package/lib/vite/traceViewer/recorder.7Wl6HrQl.js +550 -0
  142. package/lib/vite/traceViewer/recorder.B_SY1GJM.css +0 -0
  143. package/lib/vite/traceViewer/recorder.BufKu9Hp.js +550 -0
  144. package/lib/vite/traceViewer/recorder.Ch-WHviK.js +2 -0
  145. package/lib/vite/traceViewer/recorder.DBDpiNOK.css +15 -0
  146. package/lib/vite/traceViewer/recorder.POd-toIn.js +2 -0
  147. package/lib/vite/traceViewer/recorder.am-MV-DQ.js +550 -0
  148. package/lib/vite/traceViewer/recorder.html +17 -0
  149. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  150. package/lib/vite/traceViewer/uiMode.BEZVCe5O.js +5 -0
  151. package/lib/vite/traceViewer/uiMode.BZoFj6zV.js +1723 -0
  152. package/lib/vite/traceViewer/uiMode.C4nbcio6.js +1730 -0
  153. package/lib/vite/traceViewer/uiMode.CAYqod-m.css +1 -0
  154. package/lib/vite/traceViewer/uiMode.DRmgrHSk.css +1462 -0
  155. package/lib/vite/traceViewer/uiMode.DdtUZZVS.js +5 -0
  156. package/lib/vite/traceViewer/uiMode.Dlo9s_YX.js +1723 -0
  157. package/lib/vite/traceViewer/uiMode.O07awP3T.js +10 -0
  158. package/lib/vite/traceViewer/uiMode.gGHHTsyL.js +1730 -0
  159. package/lib/vite/traceViewer/uiMode.html +6 -4
  160. package/lib/vite/traceViewer/uiMode.wsGnVMQK.js +1723 -0
  161. package/lib/vite/traceViewer/workbench.BQNDbcQ0.css +550 -0
  162. package/lib/vite/traceViewer/workbench.DjbIuxix.css +1 -0
  163. package/lib/vite/traceViewer/workbench.DlsCx8k5.css +1 -0
  164. package/lib/vite/traceViewer/workbench.wuxQoE2z.css +3703 -0
  165. package/package.json +1 -1
  166. package/types/protocol.d.ts +610 -173
  167. package/types/types.d.ts +2037 -949
package/browsers.json CHANGED
@@ -3,31 +3,31 @@
3
3
  "browsers": [
4
4
  {
5
5
  "name": "chromium",
6
- "revision": "1134",
6
+ "revision": "1140",
7
7
  "installByDefault": true,
8
- "browserVersion": "129.0.6668.29"
8
+ "browserVersion": "130.0.6723.31"
9
9
  },
10
10
  {
11
11
  "name": "chromium-tip-of-tree",
12
- "revision": "1256",
12
+ "revision": "1264",
13
13
  "installByDefault": false,
14
- "browserVersion": "130.0.6695.0"
14
+ "browserVersion": "131.0.6740.0"
15
15
  },
16
16
  {
17
17
  "name": "firefox",
18
- "revision": "1463",
18
+ "revision": "1465",
19
19
  "installByDefault": true,
20
- "browserVersion": "130.0"
20
+ "browserVersion": "131.0"
21
21
  },
22
22
  {
23
23
  "name": "firefox-beta",
24
- "revision": "1462",
24
+ "revision": "1464",
25
25
  "installByDefault": false,
26
- "browserVersion": "130.0b2"
26
+ "browserVersion": "131.0b2"
27
27
  },
28
28
  {
29
29
  "name": "webkit",
30
- "revision": "2070",
30
+ "revision": "2083",
31
31
  "installByDefault": true,
32
32
  "revisionOverrides": {
33
33
  "mac10.14": "1446",
@@ -42,7 +42,11 @@
42
42
  {
43
43
  "name": "ffmpeg",
44
44
  "revision": "1010",
45
- "installByDefault": true
45
+ "installByDefault": true,
46
+ "revisionOverrides": {
47
+ "mac12": "1010",
48
+ "mac12-arm64": "1010"
49
+ }
46
50
  },
47
51
  {
48
52
  "name": "android",
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /**
8
+ * Copyright (c) 2009-2020 Lodash.
9
+ * Taken from: https://github.com/lodash/lodash/blob/main/src/escapeRegExp.ts
10
+ * Used to match `RegExp`
11
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
12
+ */
13
+ const reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
14
+ const reHasRegExpChar = RegExp(reRegExpChar.source);
15
+
16
+ /**
17
+ * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
18
+ * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
19
+ *
20
+ * @since 3.0.0
21
+ * @category String
22
+ * @param {string} [string=''] The string to escape.
23
+ * @returns {string} Returns the escaped string.
24
+ * @see escape, escapeRegExp, unescape
25
+ * @example
26
+ *
27
+ * escapeRegExp('[lodash](https://lodash.com/)')
28
+ * // => '\[lodash\]\(https://lodash\.com/\)'
29
+ */
30
+ function escapeRegExp(string) {
31
+ return string && reHasRegExpChar.test(string) ? string.replace(reRegExpChar, '\\$&') : string || '';
32
+ }
33
+ var _default = exports.default = escapeRegExp;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.secretsFilter = void 0;
7
+ var _escapeRegExp = _interopRequireDefault(require("./escapeRegExp"));
8
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ /* Copyright Checkly
10
+ */
11
+
12
+ const IdentityFunction = s => s;
13
+ const secretsFilter = () => {
14
+ const disabled = process.env['CHECKLY_INTERNAL_ENABLE_PATCHED_TRACING'] !== 'true';
15
+ if (disabled) return IdentityFunction;
16
+ const keys = process.env['CHECKLY_INTERNAL_REPLACE_TRACE_KEYS'] || '[]';
17
+ const keylist = JSON.parse(keys);
18
+ if (keylist.length === 0) return IdentityFunction;
19
+ const escapedList = keylist.map(_escapeRegExp.default);
20
+ const regex = new RegExp(escapedList.join('|'), 'g');
21
+ return s => s.replaceAll(regex, '*********');
22
+ };
23
+ exports.secretsFilter = secretsFilter;
@@ -238,13 +238,10 @@ _utilsBundle.program.command('show-trace [trace...]').option('-b, --browser <bro
238
238
  Examples:
239
239
 
240
240
  $ show-trace https://example.com/trace.zip`);
241
- async function launchContext(options, headless, executablePath) {
241
+ async function launchContext(options, extraOptions) {
242
242
  validateOptions(options);
243
243
  const browserType = lookupBrowserType(options);
244
- const launchOptions = {
245
- headless,
246
- executablePath
247
- };
244
+ const launchOptions = extraOptions;
248
245
  if (options.channel) launchOptions.channel = options.channel;
249
246
  launchOptions.handleSIGINT = false;
250
247
  const contextOptions =
@@ -256,7 +253,7 @@ async function launchContext(options, headless, executablePath) {
256
253
  // In headful mode, use host device scale factor for things to look nice.
257
254
  // In headless, keep things the way it works in Playwright by default.
258
255
  // Assume high-dpi on MacOS. TODO: this is not perfect.
259
- if (!headless) contextOptions.deviceScaleFactor = _os.default.platform() === 'darwin' ? 2 : 1;
256
+ if (!extraOptions.headless) contextOptions.deviceScaleFactor = _os.default.platform() === 'darwin' ? 2 : 1;
260
257
 
261
258
  // Work around the WebKit GTK scrolling issue.
262
259
  if (browserType.name() === 'webkit' && process.platform === 'linux') {
@@ -281,7 +278,7 @@ async function launchContext(options, headless, executablePath) {
281
278
  process.stdout.write(text);
282
279
  process.stdout.write('\n-------------8<-------------\n');
283
280
  const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
284
- if (autoExitCondition && text.includes(autoExitCondition)) Promise.all(context.pages().map(async p => p.close()));
281
+ if (autoExitCondition && text.includes(autoExitCondition)) closeBrowser();
285
282
  };
286
283
  // Make sure we exit abnormally when browser crashes.
287
284
  const logs = [];
@@ -383,7 +380,7 @@ async function launchContext(options, headless, executablePath) {
383
380
  const hasPage = browser.contexts().some(context => context.pages().length > 0);
384
381
  if (hasPage) return;
385
382
  // Avoid the error when the last page is closed because the browser has been closed.
386
- closeBrowser().catch(e => null);
383
+ closeBrowser().catch(() => {});
387
384
  });
388
385
  });
389
386
  process.on('SIGINT', async () => {
@@ -431,7 +428,10 @@ async function open(options, url, language) {
431
428
  context,
432
429
  launchOptions,
433
430
  contextOptions
434
- } = await launchContext(options, !!process.env.PWTEST_CLI_HEADLESS, process.env.PWTEST_CLI_EXECUTABLE_PATH);
431
+ } = await launchContext(options, {
432
+ headless: !!process.env.PWTEST_CLI_HEADLESS,
433
+ executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH
434
+ });
435
435
  await context._enableRecorder({
436
436
  language,
437
437
  launchOptions,
@@ -447,11 +447,16 @@ async function codegen(options, url) {
447
447
  output: outputFile,
448
448
  testIdAttribute: testIdAttributeName
449
449
  } = options;
450
+ const tracesDir = _path.default.join(_os.default.tmpdir(), `playwright-recorder-trace-${Date.now()}`);
450
451
  const {
451
452
  context,
452
453
  launchOptions,
453
454
  contextOptions
454
- } = await launchContext(options, !!process.env.PWTEST_CLI_HEADLESS, process.env.PWTEST_CLI_EXECUTABLE_PATH);
455
+ } = await launchContext(options, {
456
+ headless: !!process.env.PWTEST_CLI_HEADLESS,
457
+ executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH,
458
+ tracesDir
459
+ });
455
460
  _utilsBundle.dotenv.config({
456
461
  path: 'playwright.env'
457
462
  });
@@ -462,6 +467,7 @@ async function codegen(options, url) {
462
467
  device: options.device,
463
468
  saveStorage: options.saveStorage,
464
469
  mode: 'recording',
470
+ codegenMode: process.env.PW_RECORDER_IS_TRACE_VIEWER ? 'trace-events' : 'actions',
465
471
  testIdAttributeName,
466
472
  outputFile: outputFile ? _path.default.resolve(outputFile) : undefined
467
473
  });
@@ -480,7 +486,9 @@ async function waitForPage(page, captureOptions) {
480
486
  async function screenshot(options, captureOptions, url, path) {
481
487
  const {
482
488
  context
483
- } = await launchContext(options, true);
489
+ } = await launchContext(options, {
490
+ headless: true
491
+ });
484
492
  console.log('Navigating to ' + url);
485
493
  const page = await openPage(context, url);
486
494
  await waitForPage(page, captureOptions);
@@ -499,7 +507,9 @@ async function pdf(options, captureOptions, url, path) {
499
507
  } = await launchContext({
500
508
  ...options,
501
509
  browser: 'chromium'
502
- }, true);
510
+ }, {
511
+ headless: true
512
+ });
503
513
  console.log('Navigating to ' + url);
504
514
  const page = await openPage(context, url);
505
515
  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
  }
@@ -163,7 +167,7 @@ class ChannelOwner extends _eventEmitter.EventEmitter {
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
+ isInternal = isInternal || this._isInternalType;
167
171
  if (isInternal) apiName = undefined;
168
172
 
169
173
  // Enclosing zone could have provided the apiName and wallTime.
@@ -187,7 +191,6 @@ class ChannelOwner extends _eventEmitter.EventEmitter {
187
191
  stepId
188
192
  };
189
193
  const result = await _zones.zones.run('apiZone', apiZone, async () => await func(apiZone));
190
- // @ts-ignore
191
194
  csi === null || csi === void 0 || csi.onApiCallEnd(callCookie, null, result);
192
195
  logApiCall(logger, `<= ${apiName} succeeded`, isInternal);
193
196
  return result;
@@ -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;
@@ -154,8 +154,9 @@ class APIRequestContext extends _channelOwner.ChannelOwner {
154
154
  (0, _utils.assert)(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' must be greater than or equal to '0'`);
155
155
  (0, _utils.assert)(options.maxRetries === undefined || options.maxRetries >= 0, `'maxRetries' must be greater than or equal to '0'`);
156
156
  const url = options.url !== undefined ? options.url : options.request.url();
157
- const params = mapParamsToArray(options.params);
158
157
  const method = options.method || ((_options$request = options.request) === null || _options$request === void 0 ? void 0 : _options$request.method());
158
+ let encodedParams = undefined;
159
+ if (typeof options.params === 'string') encodedParams = options.params;else if (options.params instanceof URLSearchParams) encodedParams = options.params.toString();
159
160
  // Cannot call allHeaders() here as the request may be paused inside route handler.
160
161
  const headersObj = options.headers || ((_options$request2 = options.request) === null || _options$request2 === void 0 ? void 0 : _options$request2.headers());
161
162
  const headers = headersObj ? (0, _utils.headersObjectToArray)(headersObj) : undefined;
@@ -174,7 +175,18 @@ class APIRequestContext extends _channelOwner.ChannelOwner {
174
175
  throw new Error(`Unexpected 'data' type`);
175
176
  }
176
177
  } else if (options.form) {
177
- formData = objectToArray(options.form);
178
+ if (globalThis.FormData && options.form instanceof FormData) {
179
+ formData = [];
180
+ for (const [name, value] of options.form.entries()) {
181
+ if (typeof value !== 'string') throw new Error(`Expected string for options.form["${name}"], found File. Please use options.multipart instead.`);
182
+ formData.push({
183
+ name,
184
+ value
185
+ });
186
+ }
187
+ } else {
188
+ formData = objectToArray(options.form);
189
+ }
178
190
  } else if (options.multipart) {
179
191
  multipartData = [];
180
192
  if (globalThis.FormData && options.multipart instanceof FormData) {
@@ -208,7 +220,8 @@ class APIRequestContext extends _channelOwner.ChannelOwner {
208
220
  };
209
221
  const result = await this._channel.fetch({
210
222
  url,
211
- params,
223
+ params: typeof options.params === 'object' ? objectToArray(options.params) : undefined,
224
+ encodedParams,
212
225
  method,
213
226
  headers,
214
227
  postData: postDataBuffer,
@@ -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,
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.WebSocket = exports.RouteHandler = exports.Route = exports.Response = exports.Request = exports.RawHeaders = void 0;
6
+ exports.WebSocketRouteHandler = exports.WebSocketRoute = exports.WebSocket = exports.RouteHandler = exports.Route = exports.Response = exports.Request = exports.RawHeaders = void 0;
7
7
  exports.validateHeaders = validateHeaders;
8
8
  var _url = require("url");
9
9
  var _channelOwner = require("./channelOwner");
@@ -17,7 +17,7 @@ var _events = require("./events");
17
17
  var _waiter = require("./waiter");
18
18
  var _fetch = require("./fetch");
19
19
  var _errors = require("./errors");
20
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
+ let _Symbol$asyncDispose;
21
21
  /**
22
22
  * Copyright (c) Microsoft Corporation.
23
23
  *
@@ -33,7 +33,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
33
33
  * See the License for the specific language governing permissions and
34
34
  * limitations under the License.
35
35
  */
36
-
36
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
37
37
  class Request extends _channelOwner.ChannelOwner {
38
38
  static from(request) {
39
39
  return request._object;
@@ -203,6 +203,7 @@ class Route extends _channelOwner.ChannelOwner {
203
203
  this._handlingPromise = null;
204
204
  this._context = void 0;
205
205
  this._didThrow = false;
206
+ this.markAsInternalType();
206
207
  }
207
208
  request() {
208
209
  return Request.from(this._initializer.request);
@@ -225,7 +226,6 @@ class Route extends _channelOwner.ChannelOwner {
225
226
  async abort(errorCode) {
226
227
  await this._handleRoute(async () => {
227
228
  await this._raceWithTargetClose(this._channel.abort({
228
- requestUrl: this.request()._initializer.url,
229
229
  errorCode
230
230
  }));
231
231
  });
@@ -302,7 +302,6 @@ class Route extends _channelOwner.ChannelOwner {
302
302
  if (options.contentType) headers['content-type'] = String(options.contentType);else if (options.json) headers['content-type'] = 'application/json';else if (options.path) headers['content-type'] = _utilsBundle.mime.getType(options.path) || 'application/octet-stream';
303
303
  if (length && !('content-length' in headers)) headers['content-length'] = String(length);
304
304
  await this._raceWithTargetClose(this._channel.fulfill({
305
- requestUrl: this.request()._initializer.url,
306
305
  status: statusOption || 200,
307
306
  headers: (0, _utils.headersObjectToArray)(headers),
308
307
  body,
@@ -313,7 +312,7 @@ class Route extends _channelOwner.ChannelOwner {
313
312
  async continue(options = {}) {
314
313
  await this._handleRoute(async () => {
315
314
  this.request()._applyFallbackOverrides(options);
316
- await this._innerContinue();
315
+ await this._innerContinue(false /* isFallback */);
317
316
  });
318
317
  }
319
318
  _checkNotHandled() {
@@ -324,21 +323,180 @@ class Route extends _channelOwner.ChannelOwner {
324
323
  this._handlingPromise = null;
325
324
  chain.resolve(done);
326
325
  }
327
- async _innerContinue(internal = false) {
326
+ async _innerContinue(isFallback) {
328
327
  const options = this.request()._fallbackOverridesForContinue();
329
- return await this._wrapApiCall(async () => {
330
- await this._raceWithTargetClose(this._channel.continue({
331
- requestUrl: this.request()._initializer.url,
332
- url: options.url,
333
- method: options.method,
334
- headers: options.headers ? (0, _utils.headersObjectToArray)(options.headers) : undefined,
335
- postData: options.postDataBuffer,
336
- isFallback: internal
337
- }));
338
- }, !!internal);
328
+ return await this._raceWithTargetClose(this._channel.continue({
329
+ url: options.url,
330
+ method: options.method,
331
+ headers: options.headers ? (0, _utils.headersObjectToArray)(options.headers) : undefined,
332
+ postData: options.postDataBuffer,
333
+ isFallback
334
+ }));
339
335
  }
340
336
  }
341
337
  exports.Route = Route;
338
+ _Symbol$asyncDispose = Symbol.asyncDispose;
339
+ class WebSocketRoute extends _channelOwner.ChannelOwner {
340
+ static from(route) {
341
+ return route._object;
342
+ }
343
+ constructor(parent, type, guid, initializer) {
344
+ super(parent, type, guid, initializer);
345
+ this._onPageMessage = void 0;
346
+ this._onPageClose = void 0;
347
+ this._onServerMessage = void 0;
348
+ this._onServerClose = void 0;
349
+ this._server = void 0;
350
+ this._connected = false;
351
+ this.markAsInternalType();
352
+ this._server = {
353
+ onMessage: handler => {
354
+ this._onServerMessage = handler;
355
+ },
356
+ onClose: handler => {
357
+ this._onServerClose = handler;
358
+ },
359
+ connectToServer: () => {
360
+ throw new Error(`connectToServer must be called on the page-side WebSocketRoute`);
361
+ },
362
+ url: () => {
363
+ return this._initializer.url;
364
+ },
365
+ close: async (options = {}) => {
366
+ await this._channel.closeServer({
367
+ ...options,
368
+ wasClean: true
369
+ }).catch(() => {});
370
+ },
371
+ send: message => {
372
+ if ((0, _utils.isString)(message)) this._channel.sendToServer({
373
+ message,
374
+ isBase64: false
375
+ }).catch(() => {});else this._channel.sendToServer({
376
+ message: message.toString('base64'),
377
+ isBase64: true
378
+ }).catch(() => {});
379
+ },
380
+ async [Symbol.asyncDispose]() {
381
+ await this.close();
382
+ }
383
+ };
384
+ this._channel.on('messageFromPage', ({
385
+ message,
386
+ isBase64
387
+ }) => {
388
+ if (this._onPageMessage) this._onPageMessage(isBase64 ? Buffer.from(message, 'base64') : message);else if (this._connected) this._channel.sendToServer({
389
+ message,
390
+ isBase64
391
+ }).catch(() => {});
392
+ });
393
+ this._channel.on('messageFromServer', ({
394
+ message,
395
+ isBase64
396
+ }) => {
397
+ if (this._onServerMessage) this._onServerMessage(isBase64 ? Buffer.from(message, 'base64') : message);else this._channel.sendToPage({
398
+ message,
399
+ isBase64
400
+ }).catch(() => {});
401
+ });
402
+ this._channel.on('closePage', ({
403
+ code,
404
+ reason,
405
+ wasClean
406
+ }) => {
407
+ if (this._onPageClose) this._onPageClose(code, reason);else this._channel.closeServer({
408
+ code,
409
+ reason,
410
+ wasClean
411
+ }).catch(() => {});
412
+ });
413
+ this._channel.on('closeServer', ({
414
+ code,
415
+ reason,
416
+ wasClean
417
+ }) => {
418
+ if (this._onServerClose) this._onServerClose(code, reason);else this._channel.closePage({
419
+ code,
420
+ reason,
421
+ wasClean
422
+ }).catch(() => {});
423
+ });
424
+ }
425
+ url() {
426
+ return this._initializer.url;
427
+ }
428
+ async close(options = {}) {
429
+ await this._channel.closePage({
430
+ ...options,
431
+ wasClean: true
432
+ }).catch(() => {});
433
+ }
434
+ connectToServer() {
435
+ if (this._connected) throw new Error('Already connected to the server');
436
+ this._connected = true;
437
+ this._channel.connect().catch(() => {});
438
+ return this._server;
439
+ }
440
+ send(message) {
441
+ if ((0, _utils.isString)(message)) this._channel.sendToPage({
442
+ message,
443
+ isBase64: false
444
+ }).catch(() => {});else this._channel.sendToPage({
445
+ message: message.toString('base64'),
446
+ isBase64: true
447
+ }).catch(() => {});
448
+ }
449
+ onMessage(handler) {
450
+ this._onPageMessage = handler;
451
+ }
452
+ onClose(handler) {
453
+ this._onPageClose = handler;
454
+ }
455
+ async [_Symbol$asyncDispose]() {
456
+ await this.close();
457
+ }
458
+ async _afterHandle() {
459
+ if (this._connected) return;
460
+ // Ensure that websocket is "open" and can send messages without an actual server connection.
461
+ await this._channel.ensureOpened();
462
+ }
463
+ }
464
+ exports.WebSocketRoute = WebSocketRoute;
465
+ class WebSocketRouteHandler {
466
+ constructor(baseURL, url, handler) {
467
+ this._baseURL = void 0;
468
+ this.url = void 0;
469
+ this.handler = void 0;
470
+ this._baseURL = baseURL;
471
+ this.url = url;
472
+ this.handler = handler;
473
+ }
474
+ static prepareInterceptionPatterns(handlers) {
475
+ const patterns = [];
476
+ let all = false;
477
+ for (const handler of handlers) {
478
+ if ((0, _utils.isString)(handler.url)) patterns.push({
479
+ glob: handler.url
480
+ });else if ((0, _utils.isRegExp)(handler.url)) patterns.push({
481
+ regexSource: handler.url.source,
482
+ regexFlags: handler.url.flags
483
+ });else all = true;
484
+ }
485
+ if (all) return [{
486
+ glob: '**/*'
487
+ }];
488
+ return patterns;
489
+ }
490
+ matches(wsURL) {
491
+ return (0, _utils.urlMatches)(this._baseURL, wsURL, this.url);
492
+ }
493
+ async handle(webSocketRoute) {
494
+ const handler = this.handler;
495
+ await handler(webSocketRoute);
496
+ await webSocketRoute._afterHandle();
497
+ }
498
+ }
499
+ exports.WebSocketRouteHandler = WebSocketRouteHandler;
342
500
  class Response extends _channelOwner.ChannelOwner {
343
501
  static from(response) {
344
502
  return response._object;