@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.
- package/lib/browserServerImpl.js +1 -1
- package/lib/cli/driver.js +11 -3
- package/lib/cli/program.js +13 -5
- package/lib/client/android.js +1 -1
- package/lib/client/artifact.js +2 -2
- package/lib/client/browserContext.js +5 -5
- package/lib/client/browserType.js +1 -1
- package/lib/client/channelOwner.js +3 -3
- package/lib/client/clientHelper.js +5 -1
- package/lib/client/connection.js +2 -2
- package/lib/client/consoleMessage.js +3 -3
- package/lib/client/electron.js +3 -0
- package/lib/client/events.js +1 -0
- package/lib/client/fetch.js +3 -3
- package/lib/client/frame.js +4 -3
- package/lib/client/harRouter.js +7 -1
- package/lib/client/locator.js +2 -2
- package/lib/client/page.js +26 -7
- package/lib/common/socksProxy.js +12 -17
- package/lib/generated/consoleApiSource.js +1 -1
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/recorderSource.js +1 -1
- package/lib/outofprocess.js +3 -3
- package/lib/protocol/validator.js +46 -29
- package/lib/remote/playwrightConnection.js +2 -2
- package/lib/remote/playwrightServer.js +72 -166
- package/lib/server/android/android.js +2 -2
- package/lib/server/android/backendAdb.js +2 -2
- package/lib/server/browser.js +2 -2
- package/lib/server/browserContext.js +8 -9
- package/lib/server/browserType.js +5 -5
- package/lib/server/chromium/chromium.js +5 -4
- package/lib/server/chromium/crBrowser.js +2 -3
- package/lib/server/chromium/crConnection.js +2 -2
- package/lib/server/chromium/crExecutionContext.js +2 -2
- package/lib/server/chromium/crInput.js +2 -2
- package/lib/server/chromium/crNetworkManager.js +10 -11
- package/lib/server/chromium/crPage.js +48 -7
- package/lib/server/chromium/crServiceWorker.js +2 -3
- package/lib/server/console.js +1 -3
- package/lib/server/debugController.js +0 -3
- package/lib/server/deviceDescriptorsSource.json +50 -50
- package/lib/server/dispatchers/browserContextDispatcher.js +7 -6
- package/lib/server/dispatchers/dispatcher.js +19 -20
- package/lib/server/dispatchers/electronDispatcher.js +13 -0
- package/lib/server/dispatchers/frameDispatcher.js +0 -6
- package/lib/server/dispatchers/localUtilsDispatcher.js +4 -4
- package/lib/server/dispatchers/pageDispatcher.js +14 -10
- package/lib/server/dispatchers/playwrightDispatcher.js +5 -5
- package/lib/server/dispatchers/writableStreamDispatcher.js +2 -2
- package/lib/server/dom.js +133 -170
- package/lib/server/electron/electron.js +40 -14
- package/lib/server/electron/loader.js +4 -2
- package/lib/server/fetch.js +4 -4
- package/lib/server/firefox/ffAccessibility.js +2 -1
- package/lib/server/firefox/ffBrowser.js +3 -3
- package/lib/server/firefox/ffConnection.js +1 -1
- package/lib/server/firefox/ffExecutionContext.js +2 -2
- package/lib/server/firefox/ffNetworkManager.js +7 -7
- package/lib/server/firefox/ffPage.js +3 -5
- package/lib/server/firefox/firefox.js +2 -2
- package/lib/server/frames.js +42 -23
- package/lib/server/har/harTracer.js +6 -6
- package/lib/server/helper.js +1 -1
- package/lib/server/input.js +2 -2
- package/lib/server/isomorphic/utilityScriptSerializers.js +0 -1
- package/lib/server/javascript.js +2 -2
- package/lib/server/page.js +51 -7
- package/lib/server/pipeTransport.js +1 -1
- package/lib/server/playwright.js +1 -1
- package/lib/server/progress.js +5 -14
- package/lib/server/recorder/csharp.js +1 -1
- package/lib/server/recorder/recorderUtils.js +2 -2
- package/lib/server/recorder.js +14 -14
- package/lib/server/registry/browserFetcher.js +1 -2
- package/lib/server/registry/dependencies.js +7 -6
- package/lib/server/registry/index.js +50 -33
- package/lib/server/registry/nativeDeps.js +0 -94
- package/lib/server/registry/oopDownloadBrowserMain.js +2 -2
- package/lib/server/screenshotter.js +0 -1
- package/lib/server/socksInterceptor.js +2 -2
- package/lib/server/trace/recorder/snapshotter.js +2 -2
- package/lib/server/trace/recorder/tracing.js +12 -11
- package/lib/server/trace/test/inMemorySnapshotter.js +1 -1
- package/lib/server/trace/viewer/traceViewer.js +2 -2
- package/lib/server/transport.js +15 -13
- package/lib/server/webkit/wkBrowser.js +3 -3
- package/lib/server/webkit/wkConnection.js +1 -1
- package/lib/server/webkit/wkExecutionContext.js +2 -2
- package/lib/server/webkit/wkInput.js +2 -2
- package/lib/server/webkit/wkInterceptableRequest.js +2 -2
- package/lib/server/webkit/wkPage.js +10 -12
- package/lib/utils/comparators.js +4 -4
- package/lib/utils/fileUtils.js +4 -0
- package/lib/utils/happy-eyeballs.js +5 -4
- package/lib/utils/hostPlatform.js +1 -1
- package/lib/utils/index.js +11 -0
- package/lib/utils/isomorphic/cssParser.js +2 -2
- package/lib/utils/isomorphic/locatorParser.js +6 -4
- package/lib/utils/isomorphic/selectorParser.js +0 -1
- package/lib/utils/network.js +33 -0
- package/lib/utils/processLauncher.js +9 -2
- package/lib/utils/profiler.js +2 -2
- package/lib/utils/zipFile.js +1 -1
- package/lib/vite/htmlReport/index.html +12 -13
- package/lib/vite/recorder/assets/codeMirrorModule-Hs9-1ZG4.css +1 -0
- package/lib/vite/recorder/assets/codeMirrorModule-I9ks4y7D.js +24 -0
- package/lib/vite/recorder/assets/{index-64ce22d5.css → index-ljsTwXtJ.css} +1 -1
- package/lib/vite/recorder/assets/index-yg8ypzl6.js +47 -0
- package/lib/vite/recorder/index.html +2 -3
- package/lib/vite/traceViewer/assets/codeMirrorModule-A2_PGeGB.js +24 -0
- package/lib/vite/{recorder/assets/codeMirrorModule-85487eb6.js → traceViewer/assets/codeMirrorModule-aUzO-LID.js} +1 -1
- package/lib/vite/traceViewer/assets/wsPort-L8WBvZfK.js +69 -0
- package/lib/vite/traceViewer/assets/wsPort-uVqol1LI.js +69 -0
- package/lib/vite/traceViewer/index.4xhUWj1f.js +2 -0
- package/lib/vite/traceViewer/index.html +4 -5
- package/lib/vite/traceViewer/index.o6j3Cv4u.js +2 -0
- package/lib/vite/traceViewer/sw.bundle.js +4 -4
- package/lib/vite/traceViewer/uiMode.PlLkrJDI.js +10 -0
- package/lib/vite/traceViewer/uiMode.html +4 -5
- package/lib/vite/traceViewer/uiMode.qpn6w4df.js +10 -0
- package/lib/vite/traceViewer/wsPort.zR1WIy9-.css +1 -0
- package/package.json +1 -1
- package/lib/vite/recorder/assets/codeMirrorModule-5d0f417c.css +0 -1
- package/lib/vite/recorder/assets/index-b14c63fe.js +0 -41
- /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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
11
|
-
function _interopRequireWildcard(
|
|
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.
|
|
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(
|
|
18
|
-
function _interopRequireWildcard(
|
|
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
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
|
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
|
-
|
|
296
|
-
const result = await
|
|
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
|
-
|
|
344
|
-
|
|
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 (
|
|
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
|
|
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
|
-
|
|
466
|
-
await
|
|
467
|
-
|
|
468
|
-
progress.
|
|
469
|
-
|
|
470
|
-
const result = await this.
|
|
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
|
-
|
|
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(`
|
|
491
|
-
await
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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 (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
519
|
-
|
|
520
|
-
return
|
|
521
|
-
|
|
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
|
-
|
|
673
|
-
const result = await this.
|
|
674
|
-
return
|
|
675
|
-
|
|
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';
|