@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
@@ -13,6 +13,7 @@ var _jsHandleDispatcher = require("./jsHandleDispatcher");
13
13
  var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
14
14
  var _artifactDispatcher = require("./artifactDispatcher");
15
15
  var _utils = require("../../utils");
16
+ var _webSocketRouteDispatcher = require("./webSocketRouteDispatcher");
16
17
  /**
17
18
  * Copyright (c) Microsoft Corporation.
18
19
  *
@@ -54,6 +55,7 @@ class PageDispatcher extends _dispatcher.Dispatcher {
54
55
  this._type_Page = true;
55
56
  this._page = void 0;
56
57
  this._subscriptions = new Set();
58
+ this._webSocketInterceptionPatterns = [];
57
59
  this.adopt(mainFrame);
58
60
  this._page = page;
59
61
  this.addObjectListener(_page.Page.Events.Close, () => {
@@ -133,6 +135,9 @@ class PageDispatcher extends _dispatcher.Dispatcher {
133
135
  response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.goForward(metadata, params))
134
136
  };
135
137
  }
138
+ async requestGC(params, metadata) {
139
+ await this._page.requestGC();
140
+ }
136
141
  async registerLocatorHandler(params, metadata) {
137
142
  const uid = this._page.registerLocatorHandler(params.selector, params.noWaitAfter);
138
143
  return {
@@ -174,6 +179,10 @@ class PageDispatcher extends _dispatcher.Dispatcher {
174
179
  return true;
175
180
  });
176
181
  }
182
+ async setWebSocketInterceptionPatterns(params, metadata) {
183
+ this._webSocketInterceptionPatterns = params.patterns;
184
+ if (params.patterns.length) await _webSocketRouteDispatcher.WebSocketRouteDispatcher.installIfNeeded(this.parentScope(), this._page);
185
+ }
177
186
  async expectScreenshot(params, metadata) {
178
187
  const mask = (params.mask || []).map(({
179
188
  frame,
@@ -39,9 +39,10 @@ class PlaywrightDispatcher extends _dispatcher.Dispatcher {
39
39
  const prelaunchedAndroidDeviceDispatcher = prelaunchedAndroidDevice ? new _androidDispatcher.AndroidDeviceDispatcher(android, prelaunchedAndroidDevice) : undefined;
40
40
  super(scope, playwright, 'Playwright', {
41
41
  chromium: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.chromium),
42
- bidi: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidi),
43
42
  firefox: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.firefox),
44
43
  webkit: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.webkit),
44
+ bidiChromium: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiChromium),
45
+ bidiFirefox: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiFirefox),
45
46
  android,
46
47
  electron: new _electronDispatcher.ElectronDispatcher(scope, playwright.electron),
47
48
  utils: playwright.options.isServer ? undefined : new _localUtilsDispatcher.LocalUtilsDispatcher(scope, playwright),
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.WebSocketRouteDispatcher = void 0;
7
+ var _page = require("../page");
8
+ var _dispatcher = require("./dispatcher");
9
+ var _utils = require("../../utils");
10
+ var _pageDispatcher = require("./pageDispatcher");
11
+ var webSocketMockSource = _interopRequireWildcard(require("../../generated/webSocketMockSource"));
12
+ var _eventsHelper = require("../../utils/eventsHelper");
13
+ var _class;
14
+ /**
15
+ * Copyright (c) Microsoft Corporation.
16
+ *
17
+ * Licensed under the Apache License, Version 2.0 (the 'License');
18
+ * you may not use this file except in compliance with the License.
19
+ * You may obtain a copy of the License at
20
+ *
21
+ * http://www.apache.org/licenses/LICENSE-2.0
22
+ *
23
+ * Unless required by applicable law or agreed to in writing, software
24
+ * distributed under the License is distributed on an 'AS IS' BASIS,
25
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
+ * See the License for the specific language governing permissions and
27
+ * limitations under the License.
28
+ */
29
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
30
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
31
+ const kBindingInstalledSymbol = Symbol('webSocketRouteBindingInstalled');
32
+ const kInitScriptInstalledSymbol = Symbol('webSocketRouteInitScriptInstalled');
33
+ class WebSocketRouteDispatcher extends _dispatcher.Dispatcher {
34
+ constructor(scope, id, url, frame) {
35
+ super(scope, {
36
+ guid: 'webSocketRoute@' + (0, _utils.createGuid)()
37
+ }, 'WebSocketRoute', {
38
+ url
39
+ });
40
+ this._type_WebSocketRoute = true;
41
+ this._id = void 0;
42
+ this._frame = void 0;
43
+ this._id = id;
44
+ this._frame = frame;
45
+ this._eventListeners.push(
46
+ // When the frame navigates or detaches, there will be no more communication
47
+ // from the mock websocket, so pretend like it was closed.
48
+ _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.InternalFrameNavigatedToNewDocument, frame => {
49
+ if (frame === this._frame) this._executionContextGone();
50
+ }), _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.FrameDetached, frame => {
51
+ if (frame === this._frame) this._executionContextGone();
52
+ }), _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.Close, () => this._executionContextGone()), _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.Crash, () => this._executionContextGone()));
53
+ WebSocketRouteDispatcher._idToDispatcher.set(this._id, this);
54
+ scope._dispatchEvent('webSocketRoute', {
55
+ webSocketRoute: this
56
+ });
57
+ }
58
+ static async installIfNeeded(contextDispatcher, target) {
59
+ const context = target instanceof _page.Page ? target.context() : target;
60
+ if (!context[kBindingInstalledSymbol]) {
61
+ context[kBindingInstalledSymbol] = true;
62
+ await context.exposeBinding('__pwWebSocketBinding', false, (source, payload) => {
63
+ if (payload.type === 'onCreate') {
64
+ const pageDispatcher = _pageDispatcher.PageDispatcher.fromNullable(contextDispatcher, source.page);
65
+ let scope;
66
+ if (pageDispatcher && matchesPattern(pageDispatcher, context._options.baseURL, payload.url)) scope = pageDispatcher;else if (matchesPattern(contextDispatcher, context._options.baseURL, payload.url)) scope = contextDispatcher;
67
+ if (scope) {
68
+ new WebSocketRouteDispatcher(scope, payload.id, payload.url, source.frame);
69
+ } else {
70
+ const request = {
71
+ id: payload.id,
72
+ type: 'passthrough'
73
+ };
74
+ source.frame.evaluateExpression(`globalThis.__pwWebSocketDispatch(${JSON.stringify(request)})`).catch(() => {});
75
+ }
76
+ return;
77
+ }
78
+ const dispatcher = WebSocketRouteDispatcher._idToDispatcher.get(payload.id);
79
+ if (payload.type === 'onMessageFromPage') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('messageFromPage', {
80
+ message: payload.data.data,
81
+ isBase64: payload.data.isBase64
82
+ });
83
+ if (payload.type === 'onMessageFromServer') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('messageFromServer', {
84
+ message: payload.data.data,
85
+ isBase64: payload.data.isBase64
86
+ });
87
+ if (payload.type === 'onClosePage') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('closePage', {
88
+ code: payload.code,
89
+ reason: payload.reason,
90
+ wasClean: payload.wasClean
91
+ });
92
+ if (payload.type === 'onCloseServer') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('closeServer', {
93
+ code: payload.code,
94
+ reason: payload.reason,
95
+ wasClean: payload.wasClean
96
+ });
97
+ });
98
+ }
99
+ if (!target[kInitScriptInstalledSymbol]) {
100
+ target[kInitScriptInstalledSymbol] = true;
101
+ await target.addInitScript(`
102
+ (() => {
103
+ const module = {};
104
+ ${webSocketMockSource.source}
105
+ (module.exports.inject())(globalThis);
106
+ })();
107
+ `);
108
+ }
109
+ }
110
+ async connect(params) {
111
+ await this._evaluateAPIRequest({
112
+ id: this._id,
113
+ type: 'connect'
114
+ });
115
+ }
116
+ async ensureOpened(params) {
117
+ await this._evaluateAPIRequest({
118
+ id: this._id,
119
+ type: 'ensureOpened'
120
+ });
121
+ }
122
+ async sendToPage(params) {
123
+ await this._evaluateAPIRequest({
124
+ id: this._id,
125
+ type: 'sendToPage',
126
+ data: {
127
+ data: params.message,
128
+ isBase64: params.isBase64
129
+ }
130
+ });
131
+ }
132
+ async sendToServer(params) {
133
+ await this._evaluateAPIRequest({
134
+ id: this._id,
135
+ type: 'sendToServer',
136
+ data: {
137
+ data: params.message,
138
+ isBase64: params.isBase64
139
+ }
140
+ });
141
+ }
142
+ async closePage(params) {
143
+ await this._evaluateAPIRequest({
144
+ id: this._id,
145
+ type: 'closePage',
146
+ code: params.code,
147
+ reason: params.reason,
148
+ wasClean: params.wasClean
149
+ });
150
+ }
151
+ async closeServer(params) {
152
+ await this._evaluateAPIRequest({
153
+ id: this._id,
154
+ type: 'closeServer',
155
+ code: params.code,
156
+ reason: params.reason,
157
+ wasClean: params.wasClean
158
+ });
159
+ }
160
+ async _evaluateAPIRequest(request) {
161
+ await this._frame.evaluateExpression(`globalThis.__pwWebSocketDispatch(${JSON.stringify(request)})`).catch(() => {});
162
+ }
163
+ _onDispose() {
164
+ WebSocketRouteDispatcher._idToDispatcher.delete(this._id);
165
+ }
166
+ _executionContextGone() {
167
+ // We could enter here after being disposed upon page closure:
168
+ // - first from the recursive dispose inintiated by PageDispatcher;
169
+ // - then from our own page.on('close') listener.
170
+ if (!this._disposed) {
171
+ this._dispatchEvent('closePage', {
172
+ wasClean: true
173
+ });
174
+ this._dispatchEvent('closeServer', {
175
+ wasClean: true
176
+ });
177
+ }
178
+ }
179
+ }
180
+ exports.WebSocketRouteDispatcher = WebSocketRouteDispatcher;
181
+ _class = WebSocketRouteDispatcher;
182
+ WebSocketRouteDispatcher._idToDispatcher = new Map();
183
+ function matchesPattern(dispatcher, baseURL, url) {
184
+ for (const pattern of dispatcher._webSocketInterceptionPatterns || []) {
185
+ const urlMatch = pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags) : pattern.glob;
186
+ if ((0, _utils.urlMatches)(baseURL, url, urlMatch)) return true;
187
+ }
188
+ return false;
189
+ }
@@ -39,15 +39,22 @@ class Download {
39
39
  this.url = url;
40
40
  this._suggestedFilename = suggestedFilename;
41
41
  page._browserContext._downloads.add(this);
42
- if (suggestedFilename !== undefined) this._page.emit(_page.Page.Events.Download, this);
42
+ if (suggestedFilename !== undefined) this._fireDownloadEvent();
43
+ }
44
+ page() {
45
+ return this._page;
43
46
  }
44
47
  _filenameSuggested(suggestedFilename) {
45
48
  (0, _utils.assert)(this._suggestedFilename === undefined);
46
49
  this._suggestedFilename = suggestedFilename;
47
- this._page.emit(_page.Page.Events.Download, this);
50
+ this._fireDownloadEvent();
48
51
  }
49
52
  suggestedFilename() {
50
53
  return this._suggestedFilename;
51
54
  }
55
+ _fireDownloadEvent() {
56
+ this._page.instrumentation.onDownload(this._page, this);
57
+ this._page.emit(_page.Page.Events.Download, this);
58
+ }
52
59
  }
53
60
  exports.Download = Download;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.GlobalAPIRequestContext = exports.BrowserContextAPIRequestContext = exports.APIRequestContext = void 0;
7
+ exports.createProxyAgent = createProxyAgent;
7
8
  var _http = _interopRequireDefault(require("http"));
8
9
  var _https = _interopRequireDefault(require("https"));
9
10
  var _stream = require("stream");
@@ -21,8 +22,8 @@ var _happyEyeballs = require("../utils/happy-eyeballs");
21
22
  var _instrumentation = require("./instrumentation");
22
23
  var _progress = require("./progress");
23
24
  var _tracing = require("./trace/recorder/tracing");
24
- var _network = require("./network");
25
25
  var _socksClientCertificatesInterceptor = require("./socksClientCertificatesInterceptor");
26
+ var _tls = require("tls");
26
27
  var _fetch = require("../checkly/fetch");
27
28
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
28
29
  /**
@@ -73,7 +74,7 @@ class APIRequestContext extends _instrumentation.SdkObject {
73
74
  return uid;
74
75
  }
75
76
  async fetch(params, metadata) {
76
- var _params$method, _defaults$clientCerti;
77
+ var _params$method;
77
78
  const defaults = this._defaultOptions();
78
79
  const headers = {
79
80
  'user-agent': defaults.userAgent,
@@ -93,7 +94,9 @@ class APIRequestContext extends _instrumentation.SdkObject {
93
94
  } of params.headers) setHeader(headers, name, value);
94
95
  }
95
96
  const requestUrl = new URL(params.url, defaults.baseURL);
96
- if (params.params) {
97
+ if (params.encodedParams) {
98
+ requestUrl.search = params.encodedParams;
99
+ } else if (params.params) {
97
100
  for (const {
98
101
  name,
99
102
  value
@@ -104,23 +107,9 @@ class APIRequestContext extends _instrumentation.SdkObject {
104
107
  const method = ((_params$method = params.method) === null || _params$method === void 0 ? void 0 : _params$method.toUpperCase()) || 'GET';
105
108
  const proxy = defaults.proxy;
106
109
  let agent;
107
- // When `clientCertificates` is present, we set the `proxy` property to our own socks proxy
108
- // for the browser to use. However, we don't need it here, because we already respect
109
- // `clientCertificates` when fetching from Node.js.
110
- if (proxy && !((_defaults$clientCerti = defaults.clientCertificates) !== null && _defaults$clientCerti !== void 0 && _defaults$clientCerti.length) && proxy.server !== 'per-context' && !shouldBypassProxy(requestUrl, proxy.bypass)) {
111
- var _proxyOpts$protocol;
112
- const proxyOpts = _url.default.parse(proxy.server);
113
- if ((_proxyOpts$protocol = proxyOpts.protocol) !== null && _proxyOpts$protocol !== void 0 && _proxyOpts$protocol.startsWith('socks')) {
114
- agent = new _utilsBundle.SocksProxyAgent({
115
- host: proxyOpts.hostname,
116
- port: proxyOpts.port || undefined
117
- });
118
- } else {
119
- if (proxy.username) proxyOpts.auth = `${proxy.username}:${proxy.password || ''}`;
120
- // TODO: We should use HttpProxyAgent conditional on proxyOpts.protocol instead of always using CONNECT method.
121
- agent = new _utilsBundle.HttpsProxyAgent(proxyOpts);
122
- }
123
- }
110
+ // We skip 'per-context' in order to not break existing users. 'per-context' was previously used to
111
+ // workaround an upstream Chromium bug. Can be removed in the future.
112
+ if (proxy && proxy.server !== 'per-context' && !shouldBypassProxy(requestUrl, proxy.bypass)) agent = createProxyAgent(proxy);
124
113
  const timeout = defaults.timeoutSettings.timeout(params);
125
114
  const deadline = timeout && (0, _utils.monotonicTime)() + timeout;
126
115
  const options = {
@@ -202,6 +191,7 @@ class APIRequestContext extends _instrumentation.SdkObject {
202
191
  try {
203
192
  return await this._sendRequest(progress, url, options, postData);
204
193
  } catch (e) {
194
+ e = (0, _socksClientCertificatesInterceptor.rewriteOpenSSLErrorIfNeeded)(e);
205
195
  if (maxRetries === 0) throw e;
206
196
  if (i === maxRetries || options.deadline && (0, _utils.monotonicTime)() + backoff > options.deadline) throw new Error(`Failed after ${i + 1} attempt(s): ${e}`);
207
197
  // Retry on connection reset only.
@@ -239,10 +229,33 @@ class APIRequestContext extends _instrumentation.SdkObject {
239
229
  ...options,
240
230
  agent
241
231
  };
242
- const timings = (0, _fetch.initializeTimings)();
232
+ const checklyTimings = (0, _fetch.initializeTimings)();
233
+ const startAt = (0, _utils.monotonicTime)();
234
+ let dnsLookupAt;
235
+ let tcpConnectionAt;
236
+ let tlsHandshakeAt;
237
+ let requestFinishAt;
238
+ let serverIPAddress;
239
+ let serverPort;
240
+ let securityDetails;
241
+ const listeners = [];
243
242
  const request = requestConstructor(url, requestOptions, async response => {
244
- timings.values.response = _perf_hooks.performance.now() - timings.values.startTimeNow;
243
+ const responseAt = (0, _utils.monotonicTime)();
244
+ checklyTimings.values.response = _perf_hooks.performance.now() - checklyTimings.values.startTimeNow;
245
245
  const notifyRequestFinished = body => {
246
+ var _tlsHandshakeAt;
247
+ const endAt = (0, _utils.monotonicTime)();
248
+ // spec: http://www.softwareishard.com/blog/har-12-spec/#timings
249
+ const timings = {
250
+ send: requestFinishAt - startAt,
251
+ wait: responseAt - requestFinishAt,
252
+ receive: endAt - responseAt,
253
+ dns: dnsLookupAt ? dnsLookupAt - startAt : -1,
254
+ connect: ((_tlsHandshakeAt = tlsHandshakeAt) !== null && _tlsHandshakeAt !== void 0 ? _tlsHandshakeAt : tcpConnectionAt) - startAt,
255
+ // "If [ssl] is defined then the time is also included in the connect field "
256
+ ssl: tlsHandshakeAt ? tlsHandshakeAt - tcpConnectionAt : -1,
257
+ blocked: -1
258
+ };
246
259
  const requestFinishedEvent = {
247
260
  requestEvent,
248
261
  httpVersion: response.httpVersion,
@@ -251,7 +264,11 @@ class APIRequestContext extends _instrumentation.SdkObject {
251
264
  headers: response.headers,
252
265
  rawHeaders: response.rawHeaders,
253
266
  cookies,
254
- body
267
+ body,
268
+ timings,
269
+ serverIPAddress,
270
+ serverPort,
271
+ securityDetails
255
272
  };
256
273
  this.emit(APIRequestContext.Events.RequestFinished, requestFinishedEvent);
257
274
  };
@@ -338,7 +355,7 @@ class APIRequestContext extends _instrumentation.SdkObject {
338
355
  response.on('aborted', () => reject(new Error('aborted')));
339
356
  const chunks = [];
340
357
  const notifyBodyFinished = () => {
341
- timings.values.endAt = _perf_hooks.performance.now();
358
+ checklyTimings.values.endAt = _perf_hooks.performance.now();
342
359
  const body = Buffer.concat(chunks);
343
360
  notifyRequestFinished(body);
344
361
  fulfill({
@@ -350,10 +367,10 @@ class APIRequestContext extends _instrumentation.SdkObject {
350
367
  timings: {
351
368
  //@ts-ignore
352
369
  values: {
353
- ...timings.values,
370
+ ...checklyTimings.values,
354
371
  ..._happyEyeballs.httpHappyEyeballsTimings.values
355
372
  },
356
- agent: _happyEyeballs.httpHappyEyeballsTimings.agent || timings.agent
373
+ agent: _happyEyeballs.httpHappyEyeballsTimings.agent || checklyTimings.agent
357
374
  }
358
375
  });
359
376
  };
@@ -386,14 +403,44 @@ class APIRequestContext extends _instrumentation.SdkObject {
386
403
  body.on('data', chunk => chunks.push(chunk));
387
404
  body.on('end', notifyBodyFinished);
388
405
  });
389
- request.on('error', error => reject((0, _socksClientCertificatesInterceptor.rewriteOpenSSLErrorIfNeeded)(error)));
390
- (0, _fetch.addRequestListeners)(request, timings);
391
- const disposeListener = () => {
406
+ (0, _fetch.addRequestListeners)(request, checklyTimings);
407
+ request.on('error', reject);
408
+ listeners.push(_utils.eventsHelper.addEventListener(this, APIRequestContext.Events.Dispose, () => {
392
409
  reject(new Error('Request context disposed.'));
393
410
  request.destroy();
394
- };
395
- this.on(APIRequestContext.Events.Dispose, disposeListener);
396
- request.on('close', () => this.off(APIRequestContext.Events.Dispose, disposeListener));
411
+ }));
412
+ request.on('close', () => _utils.eventsHelper.removeEventListeners(listeners));
413
+ request.on('socket', socket => {
414
+ // happy eyeballs don't emit lookup and connect events, so we use our custom ones
415
+ const happyEyeBallsTimings = (0, _happyEyeballs.timingForSocket)(socket);
416
+ dnsLookupAt = happyEyeBallsTimings.dnsLookupAt;
417
+ tcpConnectionAt = happyEyeBallsTimings.tcpConnectionAt;
418
+
419
+ // non-happy-eyeballs sockets
420
+ listeners.push(_utils.eventsHelper.addEventListener(socket, 'lookup', () => {
421
+ dnsLookupAt = (0, _utils.monotonicTime)();
422
+ }), _utils.eventsHelper.addEventListener(socket, 'connect', () => {
423
+ tcpConnectionAt = (0, _utils.monotonicTime)();
424
+ }), _utils.eventsHelper.addEventListener(socket, 'secureConnect', () => {
425
+ tlsHandshakeAt = (0, _utils.monotonicTime)();
426
+ if (socket instanceof _tls.TLSSocket) {
427
+ var _socket$getProtocol;
428
+ const peerCertificate = socket.getPeerCertificate();
429
+ securityDetails = {
430
+ protocol: (_socket$getProtocol = socket.getProtocol()) !== null && _socket$getProtocol !== void 0 ? _socket$getProtocol : undefined,
431
+ subjectName: peerCertificate.subject.CN,
432
+ validFrom: new Date(peerCertificate.valid_from).getTime() / 1000,
433
+ validTo: new Date(peerCertificate.valid_to).getTime() / 1000,
434
+ issuer: peerCertificate.issuer.CN
435
+ };
436
+ }
437
+ }));
438
+ serverIPAddress = socket.remoteAddress;
439
+ serverPort = socket.remotePort;
440
+ });
441
+ request.on('finish', () => {
442
+ requestFinishAt = (0, _utils.monotonicTime)();
443
+ });
397
444
  progress.log(`→ ${options.method} ${url.toString()}`);
398
445
  if (options.headers) {
399
446
  for (const [name, value] of Object.entries(options.headers)) progress.log(` ${name}: ${value}`);
@@ -539,6 +586,19 @@ class GlobalAPIRequestContext extends APIRequestContext {
539
586
  }
540
587
  }
541
588
  exports.GlobalAPIRequestContext = GlobalAPIRequestContext;
589
+ function createProxyAgent(proxy) {
590
+ var _proxyOpts$protocol;
591
+ const proxyOpts = _url.default.parse(proxy.server);
592
+ if ((_proxyOpts$protocol = proxyOpts.protocol) !== null && _proxyOpts$protocol !== void 0 && _proxyOpts$protocol.startsWith('socks')) {
593
+ return new _utilsBundle.SocksProxyAgent({
594
+ host: proxyOpts.hostname,
595
+ port: proxyOpts.port || undefined
596
+ });
597
+ }
598
+ if (proxy.username) proxyOpts.auth = `${proxy.username}:${proxy.password || ''}`;
599
+ // TODO: We should use HttpProxyAgent conditional on proxyOpts.protocol instead of always using CONNECT method.
600
+ return new _utilsBundle.HttpsProxyAgent(proxyOpts);
601
+ }
542
602
  function toHeadersArray(rawHeaders) {
543
603
  const result = [];
544
604
  for (let i = 0; i < rawHeaders.length; i += 2) result.push({
@@ -549,26 +609,9 @@ function toHeadersArray(rawHeaders) {
549
609
  }
550
610
  const redirectStatus = [301, 302, 303, 307, 308];
551
611
  function parseCookie(header) {
552
- const pairs = header.split(';').filter(s => s.trim().length > 0).map(p => {
553
- let key = '';
554
- let value = '';
555
- const separatorPos = p.indexOf('=');
556
- if (separatorPos === -1) {
557
- // If only a key is specified, the value is left undefined.
558
- key = p.trim();
559
- } else {
560
- // Otherwise we assume that the key is the element before the first `=`
561
- key = p.slice(0, separatorPos).trim();
562
- // And the value is the rest of the string.
563
- value = p.slice(separatorPos + 1).trim();
564
- }
565
- return [key, value];
566
- });
567
- if (!pairs.length) return null;
568
- const [name, value] = pairs[0];
612
+ const raw = (0, _cookieStore.parseRawCookie)(header);
613
+ if (!raw) return null;
569
614
  const cookie = {
570
- name,
571
- value,
572
615
  domain: '',
573
616
  path: '',
574
617
  expires: -1,
@@ -576,55 +619,9 @@ function parseCookie(header) {
576
619
  secure: false,
577
620
  // From https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
578
621
  // The cookie-sending behavior if SameSite is not specified is SameSite=Lax.
579
- sameSite: 'Lax'
622
+ sameSite: 'Lax',
623
+ ...raw
580
624
  };
581
- for (let i = 1; i < pairs.length; i++) {
582
- const [name, value] = pairs[i];
583
- switch (name.toLowerCase()) {
584
- case 'expires':
585
- const expiresMs = +new Date(value);
586
- // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.1
587
- if (isFinite(expiresMs)) {
588
- if (expiresMs <= 0) cookie.expires = 0;else cookie.expires = Math.min(expiresMs / 1000, _network.kMaxCookieExpiresDateInSeconds);
589
- }
590
- break;
591
- case 'max-age':
592
- const maxAgeSec = parseInt(value, 10);
593
- if (isFinite(maxAgeSec)) {
594
- // From https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.2
595
- // If delta-seconds is less than or equal to zero (0), let expiry-time
596
- // be the earliest representable date and time.
597
- if (maxAgeSec <= 0) cookie.expires = 0;else cookie.expires = Math.min(Date.now() / 1000 + maxAgeSec, _network.kMaxCookieExpiresDateInSeconds);
598
- }
599
- break;
600
- case 'domain':
601
- cookie.domain = value.toLocaleLowerCase() || '';
602
- if (cookie.domain && !cookie.domain.startsWith('.') && cookie.domain.includes('.')) cookie.domain = '.' + cookie.domain;
603
- break;
604
- case 'path':
605
- cookie.path = value || '';
606
- break;
607
- case 'secure':
608
- cookie.secure = true;
609
- break;
610
- case 'httponly':
611
- cookie.httpOnly = true;
612
- break;
613
- case 'samesite':
614
- switch (value.toLowerCase()) {
615
- case 'none':
616
- cookie.sameSite = 'None';
617
- break;
618
- case 'lax':
619
- cookie.sameSite = 'Lax';
620
- break;
621
- case 'strict':
622
- cookie.sameSite = 'Strict';
623
- break;
624
- }
625
- break;
626
- }
627
- }
628
625
  return cookie;
629
626
  }
630
627
  function serializePostData(params, headers) {
@@ -53,7 +53,8 @@ class FFBrowser extends _browser.Browser {
53
53
  browser._defaultContext = new FFBrowserContext(browser, undefined, options.persistent);
54
54
  promises.push(browser._defaultContext._initialize());
55
55
  }
56
- if (options.proxy) promises.push(browser.session.send('Browser.setBrowserProxy', toJugglerProxyOptions(options.proxy)));
56
+ const proxy = options.originalLaunchOptions.proxyOverride || options.proxy;
57
+ if (proxy) promises.push(browser.session.send('Browser.setBrowserProxy', toJugglerProxyOptions(proxy)));
57
58
  await Promise.all(promises);
58
59
  return browser;
59
60
  }
@@ -205,7 +206,7 @@ class FFBrowserContext extends _browserContext.BrowserContext {
205
206
  browserContextId,
206
207
  bypassCSP: true
207
208
  }));
208
- if (this._options.ignoreHTTPSErrors) promises.push(this._browser.session.send('Browser.setIgnoreHTTPSErrors', {
209
+ if (this._options.ignoreHTTPSErrors || this._options.internalIgnoreHTTPSErrors) promises.push(this._browser.session.send('Browser.setIgnoreHTTPSErrors', {
209
210
  browserContextId,
210
211
  ignoreHTTPSErrors: true
211
212
  }));
@@ -255,10 +256,11 @@ class FFBrowserContext extends _browserContext.BrowserContext {
255
256
  });
256
257
  }));
257
258
  }
258
- if (this._options.proxy) {
259
+ const proxy = this._options.proxyOverride || this._options.proxy;
260
+ if (proxy) {
259
261
  promises.push(this._browser.session.send('Browser.setContextProxy', {
260
262
  browserContextId: this._browserContextId,
261
- ...toJugglerProxyOptions(this._options.proxy)
263
+ ...toJugglerProxyOptions(proxy)
262
264
  }));
263
265
  }
264
266
  await Promise.all(promises);
@@ -101,9 +101,6 @@ class FFExecutionContext {
101
101
  objectId
102
102
  });
103
103
  }
104
- objectCount(objectId) {
105
- throw new Error('Method not implemented in Firefox.');
106
- }
107
104
  }
108
105
  exports.FFExecutionContext = FFExecutionContext;
109
106
  function checkException(exceptionDetails) {
@@ -360,6 +360,9 @@ class FFPage {
360
360
  });
361
361
  return success;
362
362
  }
363
+ async requestGC() {
364
+ await this._session.send('Heap.collectGarbage');
365
+ }
363
366
  async addInitScript(initScript, worldName) {
364
367
  this._initScripts.push({
365
368
  initScript,
@@ -92,19 +92,8 @@ class Firefox extends _browserType.BrowserType {
92
92
  }
93
93
  }
94
94
  exports.Firefox = Firefox;
95
- class JugglerReadyState {
96
- constructor() {
97
- this._jugglerPromise = new _utils.ManualPromise();
98
- }
95
+ class JugglerReadyState extends _browserType.BrowserReadyState {
99
96
  onBrowserOutput(message) {
100
- if (message.includes('Juggler listening to the pipe')) this._jugglerPromise.resolve();
101
- }
102
- onBrowserExit() {
103
- // Unblock launch when browser prematurely exits.
104
- this._jugglerPromise.resolve();
105
- }
106
- async waitUntilReady() {
107
- await this._jugglerPromise;
108
- return {};
97
+ if (message.includes('Juggler listening to the pipe')) this._wsEndpoint.resolve(undefined);
109
98
  }
110
99
  }
@@ -165,7 +165,7 @@ class FrameSelectors {
165
165
  exports.FrameSelectors = FrameSelectors;
166
166
  async function adoptIfNeeded(handle, context) {
167
167
  if (handle._context === context) return handle;
168
- const adopted = handle._page._delegate.adoptElementHandle(handle, context);
168
+ const adopted = await handle._page._delegate.adoptElementHandle(handle, context);
169
169
  handle.dispose();
170
170
  return adopted;
171
171
  }
@@ -623,14 +623,15 @@ class Frame extends _instrumentation.SdkObject {
623
623
  if (!['attached', 'detached', 'visible', 'hidden'].includes(state)) throw new Error(`state: expected one of (attached|detached|visible|hidden)`);
624
624
  return controller.run(async progress => {
625
625
  progress.log(`waiting for ${this._asLocator(selector)}${state === 'attached' ? '' : ' to be ' + state}`);
626
- return await this.waitForSelectorInternal(progress, selector, options, scope);
626
+ return await this.waitForSelectorInternal(progress, selector, true, options, scope);
627
627
  }, this._page._timeoutSettings.timeout(options));
628
628
  }
629
- async waitForSelectorInternal(progress, selector, options, scope) {
629
+ async waitForSelectorInternal(progress, selector, performLocatorHandlersCheckpoint, options, scope) {
630
630
  const {
631
631
  state = 'visible'
632
632
  } = options;
633
633
  const promise = this.retryWithProgressAndTimeouts(progress, [0, 20, 50, 100, 100, 500], async continuePolling => {
634
+ if (performLocatorHandlersCheckpoint) await this._page.performLocatorHandlersCheckpoint(progress);
634
635
  const resolved = await this.selectors.resolveInjectedForSelector(selector, options, scope);
635
636
  progress.throwIfAborted();
636
637
  if (!resolved) {