@checkly/playwright-core 1.41.21 → 1.41.23

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 (126) hide show
  1. package/lib/browserServerImpl.js +1 -1
  2. package/lib/cli/driver.js +11 -3
  3. package/lib/cli/program.js +13 -5
  4. package/lib/client/android.js +1 -1
  5. package/lib/client/artifact.js +2 -2
  6. package/lib/client/browserContext.js +5 -5
  7. package/lib/client/browserType.js +1 -1
  8. package/lib/client/channelOwner.js +3 -3
  9. package/lib/client/clientHelper.js +5 -1
  10. package/lib/client/connection.js +2 -2
  11. package/lib/client/consoleMessage.js +3 -3
  12. package/lib/client/electron.js +3 -0
  13. package/lib/client/events.js +1 -0
  14. package/lib/client/fetch.js +3 -3
  15. package/lib/client/frame.js +4 -3
  16. package/lib/client/harRouter.js +7 -1
  17. package/lib/client/locator.js +2 -2
  18. package/lib/client/page.js +26 -7
  19. package/lib/common/socksProxy.js +12 -17
  20. package/lib/generated/consoleApiSource.js +1 -1
  21. package/lib/generated/injectedScriptSource.js +1 -1
  22. package/lib/generated/recorderSource.js +1 -1
  23. package/lib/outofprocess.js +3 -3
  24. package/lib/protocol/validator.js +46 -29
  25. package/lib/remote/playwrightConnection.js +2 -2
  26. package/lib/remote/playwrightServer.js +72 -166
  27. package/lib/server/android/android.js +2 -2
  28. package/lib/server/android/backendAdb.js +2 -2
  29. package/lib/server/browser.js +2 -2
  30. package/lib/server/browserContext.js +8 -9
  31. package/lib/server/browserType.js +5 -5
  32. package/lib/server/chromium/chromium.js +5 -4
  33. package/lib/server/chromium/crBrowser.js +2 -3
  34. package/lib/server/chromium/crConnection.js +2 -2
  35. package/lib/server/chromium/crExecutionContext.js +2 -2
  36. package/lib/server/chromium/crInput.js +2 -2
  37. package/lib/server/chromium/crNetworkManager.js +10 -11
  38. package/lib/server/chromium/crPage.js +48 -7
  39. package/lib/server/chromium/crServiceWorker.js +2 -3
  40. package/lib/server/console.js +1 -3
  41. package/lib/server/debugController.js +0 -3
  42. package/lib/server/deviceDescriptorsSource.json +50 -50
  43. package/lib/server/dispatchers/browserContextDispatcher.js +7 -6
  44. package/lib/server/dispatchers/dispatcher.js +19 -20
  45. package/lib/server/dispatchers/electronDispatcher.js +13 -0
  46. package/lib/server/dispatchers/frameDispatcher.js +0 -6
  47. package/lib/server/dispatchers/localUtilsDispatcher.js +4 -4
  48. package/lib/server/dispatchers/pageDispatcher.js +14 -10
  49. package/lib/server/dispatchers/playwrightDispatcher.js +5 -5
  50. package/lib/server/dispatchers/writableStreamDispatcher.js +2 -2
  51. package/lib/server/dom.js +133 -170
  52. package/lib/server/electron/electron.js +40 -14
  53. package/lib/server/electron/loader.js +4 -2
  54. package/lib/server/fetch.js +4 -4
  55. package/lib/server/firefox/ffAccessibility.js +2 -1
  56. package/lib/server/firefox/ffBrowser.js +3 -3
  57. package/lib/server/firefox/ffConnection.js +1 -1
  58. package/lib/server/firefox/ffExecutionContext.js +2 -2
  59. package/lib/server/firefox/ffNetworkManager.js +7 -7
  60. package/lib/server/firefox/ffPage.js +3 -5
  61. package/lib/server/firefox/firefox.js +2 -2
  62. package/lib/server/frames.js +42 -23
  63. package/lib/server/har/harTracer.js +6 -6
  64. package/lib/server/helper.js +1 -1
  65. package/lib/server/input.js +2 -2
  66. package/lib/server/isomorphic/utilityScriptSerializers.js +0 -1
  67. package/lib/server/javascript.js +2 -2
  68. package/lib/server/page.js +51 -7
  69. package/lib/server/pipeTransport.js +1 -1
  70. package/lib/server/playwright.js +1 -1
  71. package/lib/server/progress.js +5 -14
  72. package/lib/server/recorder/csharp.js +1 -1
  73. package/lib/server/recorder/recorderUtils.js +2 -2
  74. package/lib/server/recorder.js +14 -14
  75. package/lib/server/registry/browserFetcher.js +1 -2
  76. package/lib/server/registry/dependencies.js +7 -6
  77. package/lib/server/registry/index.js +50 -33
  78. package/lib/server/registry/nativeDeps.js +0 -94
  79. package/lib/server/registry/oopDownloadBrowserMain.js +2 -2
  80. package/lib/server/screenshotter.js +0 -1
  81. package/lib/server/socksInterceptor.js +2 -2
  82. package/lib/server/trace/recorder/snapshotter.js +2 -2
  83. package/lib/server/trace/recorder/tracing.js +12 -11
  84. package/lib/server/trace/test/inMemorySnapshotter.js +1 -1
  85. package/lib/server/trace/viewer/traceViewer.js +2 -2
  86. package/lib/server/transport.js +15 -13
  87. package/lib/server/webkit/wkBrowser.js +3 -3
  88. package/lib/server/webkit/wkConnection.js +1 -1
  89. package/lib/server/webkit/wkExecutionContext.js +2 -2
  90. package/lib/server/webkit/wkInput.js +2 -2
  91. package/lib/server/webkit/wkInterceptableRequest.js +2 -2
  92. package/lib/server/webkit/wkPage.js +10 -12
  93. package/lib/utils/comparators.js +4 -4
  94. package/lib/utils/fileUtils.js +4 -0
  95. package/lib/utils/happy-eyeballs.js +5 -4
  96. package/lib/utils/hostPlatform.js +1 -1
  97. package/lib/utils/index.js +11 -0
  98. package/lib/utils/isomorphic/cssParser.js +2 -2
  99. package/lib/utils/isomorphic/locatorParser.js +6 -4
  100. package/lib/utils/isomorphic/selectorParser.js +0 -1
  101. package/lib/utils/network.js +33 -0
  102. package/lib/utils/processLauncher.js +9 -2
  103. package/lib/utils/profiler.js +2 -2
  104. package/lib/utils/zipFile.js +1 -1
  105. package/lib/vite/htmlReport/index.html +12 -13
  106. package/lib/vite/recorder/assets/codeMirrorModule-Hs9-1ZG4.css +1 -0
  107. package/lib/vite/recorder/assets/codeMirrorModule-I9ks4y7D.js +24 -0
  108. package/lib/vite/recorder/assets/{index-64ce22d5.css → index-ljsTwXtJ.css} +1 -1
  109. package/lib/vite/recorder/assets/index-yg8ypzl6.js +47 -0
  110. package/lib/vite/recorder/index.html +2 -3
  111. package/lib/vite/traceViewer/assets/codeMirrorModule-A2_PGeGB.js +24 -0
  112. package/lib/vite/{recorder/assets/codeMirrorModule-85487eb6.js → traceViewer/assets/codeMirrorModule-aUzO-LID.js} +1 -1
  113. package/lib/vite/traceViewer/assets/wsPort-L8WBvZfK.js +69 -0
  114. package/lib/vite/traceViewer/assets/wsPort-uVqol1LI.js +69 -0
  115. package/lib/vite/traceViewer/index.4xhUWj1f.js +2 -0
  116. package/lib/vite/traceViewer/index.html +4 -5
  117. package/lib/vite/traceViewer/index.o6j3Cv4u.js +2 -0
  118. package/lib/vite/traceViewer/sw.bundle.js +4 -4
  119. package/lib/vite/traceViewer/uiMode.PlLkrJDI.js +10 -0
  120. package/lib/vite/traceViewer/uiMode.html +4 -5
  121. package/lib/vite/traceViewer/uiMode.qpn6w4df.js +10 -0
  122. package/lib/vite/traceViewer/wsPort.zR1WIy9-.css +1 -0
  123. package/package.json +1 -1
  124. package/lib/vite/recorder/assets/codeMirrorModule-5d0f417c.css +0 -1
  125. package/lib/vite/recorder/assets/index-b14c63fe.js +0 -41
  126. /package/lib/vite/recorder/assets/{codicon-79f233d0.ttf → codicon-zGuYmc9o.ttf} +0 -0
@@ -209,7 +209,7 @@ class LocalUtilsDispatcher extends _dispatcher.Dispatcher {
209
209
  transport.send(message);
210
210
  });
211
211
  transport.onclose = () => {
212
- socksInterceptor === null || socksInterceptor === void 0 ? void 0 : socksInterceptor.cleanup();
212
+ socksInterceptor === null || socksInterceptor === void 0 || socksInterceptor.cleanup();
213
213
  pipe.wasClosed();
214
214
  };
215
215
  pipe.on('close', () => transport.close());
@@ -360,7 +360,7 @@ class HarBackend {
360
360
  }
361
361
  dispose() {
362
362
  var _this$_zipFile;
363
- (_this$_zipFile = this._zipFile) === null || _this$_zipFile === void 0 ? void 0 : _this$_zipFile.close();
363
+ (_this$_zipFile = this._zipFile) === null || _this$_zipFile === void 0 || _this$_zipFile.close();
364
364
  }
365
365
  }
366
366
  function countMatchingHeaders(harHeaders, headers) {
@@ -374,7 +374,7 @@ function countMatchingHeaders(harHeaders, headers) {
374
374
  async function urlToWSEndpoint(progress, endpointURL) {
375
375
  var _progress$timeUntilDe;
376
376
  if (endpointURL.startsWith('ws')) return endpointURL;
377
- progress === null || progress === void 0 ? void 0 : progress.log(`<ws preparing> retrieving websocket url from ${endpointURL}`);
377
+ progress === null || progress === void 0 || progress.log(`<ws preparing> retrieving websocket url from ${endpointURL}`);
378
378
  const fetchUrl = new URL(endpointURL);
379
379
  if (!fetchUrl.pathname.endsWith('/')) fetchUrl.pathname += '/';
380
380
  fetchUrl.pathname += 'json';
@@ -388,7 +388,7 @@ async function urlToWSEndpoint(progress, endpointURL) {
388
388
  }, async (params, response) => {
389
389
  return new Error(`Unexpected status ${response.statusCode} when connecting to ${fetchUrl.toString()}.\n` + `This does not look like a Playwright server, try connecting via ws://.`);
390
390
  });
391
- progress === null || progress === void 0 ? void 0 : progress.throwIfAborted();
391
+ progress === null || progress === void 0 || progress.throwIfAborted();
392
392
  const wsUrl = new URL(endpointURL);
393
393
  let wsEndpointPath = JSON.parse(json).wsEndpointPath;
394
394
  if (wsEndpointPath.startsWith('/')) wsEndpointPath = wsEndpointPath.substring(1);
@@ -75,6 +75,9 @@ class PageDispatcher extends _dispatcher.Dispatcher {
75
75
  }));
76
76
  this.addObjectListener(_page.Page.Events.FrameAttached, frame => this._onFrameAttached(frame));
77
77
  this.addObjectListener(_page.Page.Events.FrameDetached, frame => this._onFrameDetached(frame));
78
+ this.addObjectListener(_page.Page.Events.LocatorHandlerTriggered, uid => this._dispatchEvent('locatorHandlerTriggered', {
79
+ uid
80
+ }));
78
81
  this.addObjectListener(_page.Page.Events.WebSocket, webSocket => this._dispatchEvent('webSocket', {
79
82
  webSocket: new _networkDispatchers.WebSocketDispatcher(this, webSocket)
80
83
  }));
@@ -130,6 +133,15 @@ class PageDispatcher extends _dispatcher.Dispatcher {
130
133
  response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.goForward(metadata, params))
131
134
  };
132
135
  }
136
+ async registerLocatorHandler(params, metadata) {
137
+ const uid = this._page.registerLocatorHandler(params.selector);
138
+ return {
139
+ uid
140
+ };
141
+ }
142
+ async resolveLocatorHandlerNoReply(params, metadata) {
143
+ this._page.resolveLocatorHandler(params.uid);
144
+ }
133
145
  async emulateMedia(params, metadata) {
134
146
  await this._page.emulateMedia({
135
147
  media: params.media,
@@ -160,8 +172,7 @@ class PageDispatcher extends _dispatcher.Dispatcher {
160
172
  });
161
173
  }
162
174
  async expectScreenshot(params, metadata) {
163
- var _params$screenshotOpt, _params$comparatorOpt;
164
- const mask = (((_params$screenshotOpt = params.screenshotOptions) === null || _params$screenshotOpt === void 0 ? void 0 : _params$screenshotOpt.mask) || []).map(({
175
+ const mask = (params.mask || []).map(({
165
176
  frame,
166
177
  selector
167
178
  }) => ({
@@ -175,14 +186,7 @@ class PageDispatcher extends _dispatcher.Dispatcher {
175
186
  return await this._page.expectScreenshot(metadata, {
176
187
  ...params,
177
188
  locator,
178
- comparatorOptions: {
179
- ...params.comparatorOptions,
180
- _comparator: (_params$comparatorOpt = params.comparatorOptions) === null || _params$comparatorOpt === void 0 ? void 0 : _params$comparatorOpt.comparator
181
- },
182
- screenshotOptions: {
183
- ...params.screenshotOptions,
184
- mask
185
- }
189
+ mask
186
190
  });
187
191
  }
188
192
  async screenshot(params, metadata) {
@@ -81,23 +81,23 @@ class SocksSupportDispatcher extends _dispatcher.Dispatcher {
81
81
  }
82
82
  async socksConnected(params) {
83
83
  var _this$_socksProxy;
84
- (_this$_socksProxy = this._socksProxy) === null || _this$_socksProxy === void 0 ? void 0 : _this$_socksProxy.socketConnected(params);
84
+ (_this$_socksProxy = this._socksProxy) === null || _this$_socksProxy === void 0 || _this$_socksProxy.socketConnected(params);
85
85
  }
86
86
  async socksFailed(params) {
87
87
  var _this$_socksProxy2;
88
- (_this$_socksProxy2 = this._socksProxy) === null || _this$_socksProxy2 === void 0 ? void 0 : _this$_socksProxy2.socketFailed(params);
88
+ (_this$_socksProxy2 = this._socksProxy) === null || _this$_socksProxy2 === void 0 || _this$_socksProxy2.socketFailed(params);
89
89
  }
90
90
  async socksData(params) {
91
91
  var _this$_socksProxy3;
92
- (_this$_socksProxy3 = this._socksProxy) === null || _this$_socksProxy3 === void 0 ? void 0 : _this$_socksProxy3.sendSocketData(params);
92
+ (_this$_socksProxy3 = this._socksProxy) === null || _this$_socksProxy3 === void 0 || _this$_socksProxy3.sendSocketData(params);
93
93
  }
94
94
  async socksError(params) {
95
95
  var _this$_socksProxy4;
96
- (_this$_socksProxy4 = this._socksProxy) === null || _this$_socksProxy4 === void 0 ? void 0 : _this$_socksProxy4.sendSocketError(params);
96
+ (_this$_socksProxy4 = this._socksProxy) === null || _this$_socksProxy4 === void 0 || _this$_socksProxy4.sendSocketError(params);
97
97
  }
98
98
  async socksEnd(params) {
99
99
  var _this$_socksProxy5;
100
- (_this$_socksProxy5 = this._socksProxy) === null || _this$_socksProxy5 === void 0 ? void 0 : _this$_socksProxy5.sendSocketEnd(params);
100
+ (_this$_socksProxy5 = this._socksProxy) === null || _this$_socksProxy5 === void 0 || _this$_socksProxy5.sendSocketEnd(params);
101
101
  }
102
102
  _onDispose() {
103
103
  _eventsHelper.eventsHelper.removeEventListeners(this._socksListeners);
@@ -7,8 +7,8 @@ exports.WritableStreamDispatcher = void 0;
7
7
  var _dispatcher = require("./dispatcher");
8
8
  var fs = _interopRequireWildcard(require("fs"));
9
9
  var _utils = require("../../utils");
10
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
11
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
10
+ 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); }
11
+ 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; }
12
12
  /**
13
13
  * Copyright (c) Microsoft Corporation.
14
14
  *
package/lib/server/dom.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.NonRecoverableDOMError = exports.InjectedScriptPollHandler = exports.FrameExecutionContext = exports.ElementHandle = void 0;
6
+ exports.NonRecoverableDOMError = exports.FrameExecutionContext = exports.ElementHandle = void 0;
7
7
  exports.assertDone = assertDone;
8
8
  exports.isNonRecoverableDOMError = isNonRecoverableDOMError;
9
9
  exports.kUnableToAdoptErrorMessage = void 0;
@@ -14,8 +14,8 @@ var js = _interopRequireWildcard(require("./javascript"));
14
14
  var _progress = require("./progress");
15
15
  var _utils = require("../utils");
16
16
  var _fileUploadUtils = require("./fileUploadUtils");
17
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
18
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
17
+ 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); }
18
+ 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; }
19
19
  /**
20
20
  * Copyright (c) Microsoft Corporation.
21
21
  *
@@ -136,17 +136,6 @@ class ElementHandle extends js.JSHandle {
136
136
  return 'error:notconnected';
137
137
  }
138
138
  }
139
- async evaluatePoll(progress, pageFunction, arg) {
140
- try {
141
- const utility = await this._frame._utilityContext();
142
- const poll = await utility.evaluateHandle(pageFunction, [await utility.injectedScript(), this, arg]);
143
- const pollHandler = new InjectedScriptPollHandler(progress, poll);
144
- return await pollHandler.finish();
145
- } catch (e) {
146
- if (js.isJavaScriptErrorInEvaluate(e) || (0, _protocolError.isSessionClosedError)(e)) throw e;
147
- return 'error:notconnected';
148
- }
149
- }
150
139
  async ownerFrame() {
151
140
  const frameId = await this._page._delegate.getOwnerFrame(this);
152
141
  if (!frameId) return null;
@@ -188,25 +177,19 @@ class ElementHandle extends js.JSHandle {
188
177
  return await this._page._delegate.scrollRectIntoViewIfNeeded(this, rect);
189
178
  }
190
179
  async _waitAndScrollIntoViewIfNeeded(progress, waitForVisible) {
191
- const timeouts = [0, 50, 100, 250];
192
- while (progress.isRunning()) {
193
- assertDone(throwRetargetableDOMError(await this._waitForElementStates(progress, waitForVisible ? ['visible', 'stable'] : ['stable'], false /* force */)));
194
- progress.throwIfAborted(); // Avoid action that has side-effects.
195
- const result = throwRetargetableDOMError(await this._scrollRectIntoViewIfNeeded());
196
- if (result === 'error:notvisible') {
197
- if (!waitForVisible) {
198
- var _timeouts$shift;
199
- // Wait for a timeout to avoid retrying too often when not waiting for visible.
200
- // If we wait for visible, this should be covered by _waitForElementStates instead.
201
- const timeout = (_timeouts$shift = timeouts.shift()) !== null && _timeouts$shift !== void 0 ? _timeouts$shift : 500;
202
- progress.log(` element is not displayed, retrying in ${timeout}ms`);
203
- await new Promise(f => setTimeout(f, timeout));
204
- }
205
- continue;
206
- }
207
- assertDone(result);
208
- return;
209
- }
180
+ const result = await this._retryAction(progress, 'scroll into view', async () => {
181
+ progress.log(` waiting for element to be stable`);
182
+ const waitResult = await this.evaluateInUtility(async ([injected, node, {
183
+ waitForVisible
184
+ }]) => {
185
+ return await injected.checkElementStates(node, waitForVisible ? ['visible', 'stable'] : ['stable']);
186
+ }, {
187
+ waitForVisible
188
+ });
189
+ if (waitResult) return waitResult;
190
+ return await this._scrollRectIntoViewIfNeeded();
191
+ }, {});
192
+ assertDone(throwRetargetableDOMError(result));
210
193
  }
211
194
  async scrollIntoViewIfNeeded(metadata, options = {}) {
212
195
  const controller = new _progress.ProgressController(metadata, this);
@@ -261,25 +244,10 @@ class ElementHandle extends js.JSHandle {
261
244
  y: box.y + border.top + offset.y
262
245
  };
263
246
  }
264
- async _retryPointerAction(progress, actionName, waitForEnabled, action, options) {
247
+ async _retryAction(progress, actionName, action, options) {
265
248
  let retry = 0;
266
249
  // We progressively wait longer between retries, up to 500ms.
267
250
  const waitTime = [0, 20, 100, 100, 500];
268
-
269
- // By default, we scroll with protocol method to reveal the action point.
270
- // However, that might not work to scroll from under position:sticky elements
271
- // that overlay the target element. To fight this, we cycle through different
272
- // scroll alignments. This works in most scenarios.
273
- const scrollOptions = [undefined, {
274
- block: 'end',
275
- inline: 'end'
276
- }, {
277
- block: 'center',
278
- inline: 'center'
279
- }, {
280
- block: 'start',
281
- inline: 'start'
282
- }];
283
251
  while (progress.isRunning()) {
284
252
  if (retry) {
285
253
  progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}, attempt #${retry}`);
@@ -292,8 +260,8 @@ class ElementHandle extends js.JSHandle {
292
260
  } else {
293
261
  progress.log(`attempting ${actionName} action${options.trial ? ' (trial run)' : ''}`);
294
262
  }
295
- const forceScrollOptions = scrollOptions[retry % scrollOptions.length];
296
- const result = await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);
263
+ if (!options.skipLocatorHandlersCheckpoint && !options.force) await this._frame._page.performLocatorHandlersCheckpoint(progress);
264
+ const result = await action(retry);
297
265
  ++retry;
298
266
  if (result === 'error:notvisible') {
299
267
  if (options.force) throw new NonRecoverableDOMError('Element is not visible');
@@ -305,14 +273,47 @@ class ElementHandle extends js.JSHandle {
305
273
  progress.log(' element is outside of the viewport');
306
274
  continue;
307
275
  }
276
+ if (result === 'error:optionsnotfound') {
277
+ progress.log(' did not find some options');
278
+ continue;
279
+ }
308
280
  if (typeof result === 'object' && 'hitTargetDescription' in result) {
309
281
  progress.log(` ${result.hitTargetDescription} intercepts pointer events`);
310
282
  continue;
311
283
  }
284
+ if (typeof result === 'object' && 'missingState' in result) {
285
+ progress.log(` element is not ${result.missingState}`);
286
+ continue;
287
+ }
312
288
  return result;
313
289
  }
314
290
  return 'done';
315
291
  }
292
+ async _retryPointerAction(progress, actionName, waitForEnabled, action, options) {
293
+ // Note: do not perform locator handlers checkpoint to avoid moving the mouse in the middle of a drag operation.
294
+ const skipLocatorHandlersCheckpoint = actionName === 'move and up';
295
+ return await this._retryAction(progress, actionName, async retry => {
296
+ // By default, we scroll with protocol method to reveal the action point.
297
+ // However, that might not work to scroll from under position:sticky elements
298
+ // that overlay the target element. To fight this, we cycle through different
299
+ // scroll alignments. This works in most scenarios.
300
+ const scrollOptions = [undefined, {
301
+ block: 'end',
302
+ inline: 'end'
303
+ }, {
304
+ block: 'center',
305
+ inline: 'center'
306
+ }, {
307
+ block: 'start',
308
+ inline: 'start'
309
+ }];
310
+ const forceScrollOptions = scrollOptions[retry % scrollOptions.length];
311
+ return await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);
312
+ }, {
313
+ ...options,
314
+ skipLocatorHandlersCheckpoint
315
+ });
316
+ }
316
317
  async _performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options) {
317
318
  const {
318
319
  force = false,
@@ -340,8 +341,19 @@ class ElementHandle extends js.JSHandle {
340
341
  await doScrollIntoView().catch(() => {});
341
342
  }
342
343
  if (options.__testHookBeforeStable) await options.__testHookBeforeStable();
343
- const result = await this._waitForElementStates(progress, waitForEnabled ? ['visible', 'enabled', 'stable'] : ['visible', 'stable'], force);
344
- if (result !== 'done') return result;
344
+ if (!force) {
345
+ const elementStates = waitForEnabled ? ['visible', 'enabled', 'stable'] : ['visible', 'stable'];
346
+ progress.log(` waiting for element to be ${waitForEnabled ? 'visible, enabled and stable' : 'visible and stable'}`);
347
+ const result = await this.evaluateInUtility(async ([injected, node, {
348
+ elementStates
349
+ }]) => {
350
+ return await injected.checkElementStates(node, elementStates);
351
+ }, {
352
+ elementStates
353
+ });
354
+ if (result) return result;
355
+ progress.log(` element is ${waitForEnabled ? 'visible, enabled and stable' : 'visible and stable'}`);
356
+ }
345
357
  if (options.__testHookAfterStable) await options.__testHookAfterStable();
346
358
  progress.log(' scrolling into view if needed');
347
359
  progress.throwIfAborted(); // Avoid action that has side-effects.
@@ -354,7 +366,9 @@ class ElementHandle extends js.JSHandle {
354
366
  progress.metadata.point = point;
355
367
  await progress.beforeInputAction(this);
356
368
  let hitTargetInterceptionHandle;
357
- if (!options.force) {
369
+ if (force) {
370
+ progress.log(` forcing action`);
371
+ } else {
358
372
  if (options.__testHookBeforeHitTarget) await options.__testHookBeforeHitTarget();
359
373
  const frameCheckResult = await this._checkFrameIsHitTarget(point);
360
374
  if (frameCheckResult === 'error:notconnected' || 'hitTargetDescription' in frameCheckResult) return frameCheckResult;
@@ -396,7 +410,7 @@ class ElementHandle extends js.JSHandle {
396
410
  if (hitTargetInterceptionHandle) {
397
411
  const stopHitTargetInterception = hitTargetInterceptionHandle.evaluate(h => h.stop()).catch(e => 'done').finally(() => {
398
412
  var _hitTargetInterceptio;
399
- (_hitTargetInterceptio = hitTargetInterceptionHandle) === null || _hitTargetInterceptio === void 0 ? void 0 : _hitTargetInterceptio.dispose();
413
+ (_hitTargetInterceptio = hitTargetInterceptionHandle) === null || _hitTargetInterceptio === void 0 || _hitTargetInterceptio.dispose();
400
414
  });
401
415
  if (!options.noWaitAfter) {
402
416
  // When noWaitAfter is passed, we do not want to accidentally stall on
@@ -462,22 +476,32 @@ class ElementHandle extends js.JSHandle {
462
476
  }, this._page._timeoutSettings.timeout(options));
463
477
  }
464
478
  async _selectOption(progress, elements, values, options) {
465
- const optionsToSelect = [...elements, ...values];
466
- await progress.beforeInputAction(this);
467
- return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
468
- progress.throwIfAborted(); // Avoid action that has side-effects.
469
- progress.log(' selecting specified option(s)');
470
- const result = await this.evaluatePoll(progress, ([injected, node, {
479
+ let resultingOptions = [];
480
+ await this._retryAction(progress, 'select option', async () => {
481
+ await progress.beforeInputAction(this);
482
+ if (!options.force) progress.log(` waiting for element to be visible and enabled`);
483
+ const optionsToSelect = [...elements, ...values];
484
+ const result = await this.evaluateInUtility(async ([injected, node, {
471
485
  optionsToSelect,
472
486
  force
473
487
  }]) => {
474
- return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled'], force, injected.selectOptions.bind(injected, optionsToSelect));
488
+ if (!force) {
489
+ const checkResult = await injected.checkElementStates(node, ['visible', 'enabled']);
490
+ if (checkResult) return checkResult;
491
+ }
492
+ return injected.selectOptions(node, optionsToSelect);
475
493
  }, {
476
494
  optionsToSelect,
477
495
  force: options.force
478
496
  });
497
+ if (Array.isArray(result)) {
498
+ progress.log(' selected specified option(s)');
499
+ resultingOptions = result;
500
+ return 'done';
501
+ }
479
502
  return result;
480
- });
503
+ }, options);
504
+ return resultingOptions;
481
505
  }
482
506
  async fill(metadata, value, options = {}) {
483
507
  const controller = new _progress.ProgressController(metadata, this);
@@ -487,38 +511,51 @@ class ElementHandle extends js.JSHandle {
487
511
  }, this._page._timeoutSettings.timeout(options));
488
512
  }
489
513
  async _fill(progress, value, options) {
490
- progress.log(`elementHandle.fill("${value}")`);
491
- await progress.beforeInputAction(this);
492
- return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
493
- progress.log(' waiting for element to be visible, enabled and editable');
494
- const filled = await this.evaluatePoll(progress, ([injected, node, {
495
- value,
496
- force
497
- }]) => {
498
- return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled', 'editable'], force, injected.fill.bind(injected, value));
499
- }, {
500
- value,
501
- force: options.force
502
- });
503
- progress.throwIfAborted(); // Avoid action that has side-effects.
504
- if (filled === 'error:notconnected') return filled;
505
- progress.log(' element is visible, enabled and editable');
506
- if (filled === 'needsinput') {
514
+ progress.log(` fill("${value}")`);
515
+ return await this._retryAction(progress, 'fill', async () => {
516
+ await progress.beforeInputAction(this);
517
+ return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
518
+ if (!options.force) progress.log(' waiting for element to be visible, enabled and editable');
519
+ const result = await this.evaluateInUtility(async ([injected, node, {
520
+ value,
521
+ force
522
+ }]) => {
523
+ if (!force) {
524
+ const checkResult = await injected.checkElementStates(node, ['visible', 'enabled', 'editable']);
525
+ if (checkResult) return checkResult;
526
+ }
527
+ return injected.fill(node, value);
528
+ }, {
529
+ value,
530
+ force: options.force
531
+ });
507
532
  progress.throwIfAborted(); // Avoid action that has side-effects.
508
- if (value) await this._page.keyboard.insertText(value);else await this._page.keyboard.press('Delete');
509
- } else {
510
- assertDone(filled);
511
- }
512
- return 'done';
513
- }, 'input');
533
+ if (result === 'needsinput') {
534
+ if (value) await this._page.keyboard.insertText(value);else await this._page.keyboard.press('Delete');
535
+ return 'done';
536
+ } else {
537
+ return result;
538
+ }
539
+ }, 'input');
540
+ }, options);
514
541
  }
515
542
  async selectText(metadata, options = {}) {
516
543
  const controller = new _progress.ProgressController(metadata, this);
517
544
  return controller.run(async progress => {
518
- progress.throwIfAborted(); // Avoid action that has side-effects.
519
- const result = await this.evaluatePoll(progress, ([injected, node, force]) => {
520
- return injected.waitForElementStatesAndPerformAction(node, ['visible'], force, injected.selectText.bind(injected));
521
- }, options.force);
545
+ const result = await this._retryAction(progress, 'selectText', async () => {
546
+ if (!options.force) progress.log(' waiting for element to be visible');
547
+ return await this.evaluateInUtility(async ([injected, node, {
548
+ force
549
+ }]) => {
550
+ if (!force) {
551
+ const checkResult = await injected.checkElementStates(node, ['visible']);
552
+ if (checkResult) return checkResult;
553
+ }
554
+ return injected.selectText(node);
555
+ }, {
556
+ force: options.force
557
+ });
558
+ }, options);
522
559
  assertDone(throwRetargetableDOMError(result));
523
560
  }, this._page._timeoutSettings.timeout(options));
524
561
  }
@@ -669,10 +706,12 @@ class ElementHandle extends js.JSHandle {
669
706
  async waitForElementState(metadata, state, options = {}) {
670
707
  const controller = new _progress.ProgressController(metadata, this);
671
708
  return controller.run(async progress => {
672
- progress.log(` waiting for element to be ${state}`);
673
- const result = await this.evaluatePoll(progress, ([injected, node, state]) => {
674
- return injected.waitForElementStatesAndPerformAction(node, [state], false, () => 'done');
675
- }, state);
709
+ const actionName = `wait for ${state}`;
710
+ const result = await this._retryAction(progress, actionName, async () => {
711
+ return await this.evaluateInUtility(async ([injected, node, state]) => {
712
+ return (await injected.checkElementStates(node, [state])) || 'done';
713
+ }, state);
714
+ }, {});
676
715
  assertDone(throwRetargetableDOMError(result));
677
716
  }, this._page._timeoutSettings.timeout(options));
678
717
  }
@@ -687,22 +726,6 @@ class ElementHandle extends js.JSHandle {
687
726
  }
688
727
  return this;
689
728
  }
690
- async _waitForElementStates(progress, states, force) {
691
- const title = joinWithAnd(states);
692
- progress.log(` waiting for element to be ${title}`);
693
- const result = await this.evaluatePoll(progress, ([injected, node, {
694
- states,
695
- force
696
- }]) => {
697
- return injected.waitForElementStatesAndPerformAction(node, states, force, () => 'done');
698
- }, {
699
- states,
700
- force
701
- });
702
- if (result === 'error:notconnected') return result;
703
- progress.log(` element is ${title}`);
704
- return result;
705
- }
706
729
  async _checkFrameIsHitTarget(point) {
707
730
  let frame = this._frame;
708
731
  const data = [];
@@ -751,63 +774,7 @@ class ElementHandle extends js.JSHandle {
751
774
  };
752
775
  }
753
776
  }
754
-
755
- // Handles an InjectedScriptPoll running in injected script:
756
- // - streams logs into progress;
757
- // - cancels the poll when progress cancels.
758
777
  exports.ElementHandle = ElementHandle;
759
- class InjectedScriptPollHandler {
760
- constructor(progress, poll) {
761
- this._progress = void 0;
762
- this._poll = void 0;
763
- this._progress = progress;
764
- this._poll = poll;
765
- // Ensure we cancel the poll before progress aborts and returns:
766
- // - no unnecessary work in the page;
767
- // - no possible side effects after progress promise rejects.
768
- this._progress.cleanupWhenAborted(() => this.cancel());
769
- this._streamLogs();
770
- }
771
- async _streamLogs() {
772
- while (this._poll && this._progress.isRunning()) {
773
- const log = await this._poll.evaluate(poll => poll.takeNextLogs()).catch(e => []);
774
- if (!this._poll || !this._progress.isRunning()) return;
775
- for (const entry of log) this._progress.logEntry(entry);
776
- }
777
- }
778
- async finishHandle() {
779
- try {
780
- const result = await this._poll.evaluateHandle(poll => poll.run());
781
- await this._finishInternal();
782
- return result;
783
- } finally {
784
- await this.cancel();
785
- }
786
- }
787
- async finish() {
788
- try {
789
- const result = await this._poll.evaluate(poll => poll.run());
790
- await this._finishInternal();
791
- return result;
792
- } finally {
793
- await this.cancel();
794
- }
795
- }
796
- async _finishInternal() {
797
- if (!this._poll) return;
798
- // Retrieve all the logs before continuing.
799
- const log = await this._poll.evaluate(poll => poll.takeLastLogs()).catch(e => []);
800
- for (const entry of log) this._progress.logEntry(entry);
801
- }
802
- async cancel() {
803
- if (!this._poll) return;
804
- const copy = this._poll;
805
- this._poll = null;
806
- await copy.evaluate(p => p.cancel()).catch(e => {});
807
- copy.dispose();
808
- }
809
- }
810
- exports.InjectedScriptPollHandler = InjectedScriptPollHandler;
811
778
  function throwRetargetableDOMError(result) {
812
779
  if (result === 'error:notconnected') throw new Error('Element is not attached to the DOM');
813
780
  return result;
@@ -838,8 +805,4 @@ function compensateHalfIntegerRoundingError(point) {
838
805
  const remainderY = point.y - Math.floor(point.y);
839
806
  if (remainderY > 0.49 && remainderY < 0.51) point.y -= 0.02;
840
807
  }
841
- function joinWithAnd(strings) {
842
- if (strings.length <= 1) return strings.join('');
843
- return strings.slice(0, strings.length - 1).join(', ') + ' and ' + strings[strings.length - 1];
844
- }
845
808
  const kUnableToAdoptErrorMessage = exports.kUnableToAdoptErrorMessage = 'Unable to adopt element handle from a different document';