@stablyai/internal-playwright-core 0.1.12 → 0.1.13
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/server/frames.js
CHANGED
|
@@ -52,7 +52,7 @@ var import_eventsHelper = require("./utils/eventsHelper");
|
|
|
52
52
|
var import_selectorParser = require("../utils/isomorphic/selectorParser");
|
|
53
53
|
var import_manualPromise = require("../utils/isomorphic/manualPromise");
|
|
54
54
|
var import_callLog = require("./callLog");
|
|
55
|
-
var import_healingService = require("./stably/
|
|
55
|
+
var import_healingService = require("./stably/auto_heal/healingService");
|
|
56
56
|
class NavigationAbortedError extends Error {
|
|
57
57
|
constructor(documentId, message) {
|
|
58
58
|
super(message);
|
|
@@ -70,8 +70,7 @@ class FrameManager {
|
|
|
70
70
|
this._mainFrame = void 0;
|
|
71
71
|
}
|
|
72
72
|
createDummyMainFrameIfNeeded() {
|
|
73
|
-
if (!this._mainFrame)
|
|
74
|
-
this.frameAttached(kDummyFrameId, null);
|
|
73
|
+
if (!this._mainFrame) this.frameAttached(kDummyFrameId, null);
|
|
75
74
|
}
|
|
76
75
|
dispose() {
|
|
77
76
|
for (const frame of this._frames.values()) {
|
|
@@ -88,8 +87,7 @@ class FrameManager {
|
|
|
88
87
|
return frames;
|
|
89
88
|
function collect(frame) {
|
|
90
89
|
frames.push(frame);
|
|
91
|
-
for (const subframe of frame.childFrames())
|
|
92
|
-
collect(subframe);
|
|
90
|
+
for (const subframe of frame.childFrames()) collect(subframe);
|
|
93
91
|
}
|
|
94
92
|
}
|
|
95
93
|
frame(frameId) {
|
|
@@ -116,8 +114,7 @@ class FrameManager {
|
|
|
116
114
|
}
|
|
117
115
|
}
|
|
118
116
|
async waitForSignalsCreatedBy(progress, waitAfter, action) {
|
|
119
|
-
if (!waitAfter)
|
|
120
|
-
return action();
|
|
117
|
+
if (!waitAfter) return action();
|
|
121
118
|
const barrier = new SignalBarrier(progress);
|
|
122
119
|
this._signalBarriers.add(barrier);
|
|
123
120
|
try {
|
|
@@ -131,23 +128,22 @@ class FrameManager {
|
|
|
131
128
|
}
|
|
132
129
|
}
|
|
133
130
|
frameWillPotentiallyRequestNavigation() {
|
|
134
|
-
for (const barrier of this._signalBarriers)
|
|
135
|
-
barrier.retain();
|
|
131
|
+
for (const barrier of this._signalBarriers) barrier.retain();
|
|
136
132
|
}
|
|
137
133
|
frameDidPotentiallyRequestNavigation() {
|
|
138
|
-
for (const barrier of this._signalBarriers)
|
|
139
|
-
barrier.release();
|
|
134
|
+
for (const barrier of this._signalBarriers) barrier.release();
|
|
140
135
|
}
|
|
141
136
|
frameRequestedNavigation(frameId, documentId) {
|
|
142
137
|
const frame = this._frames.get(frameId);
|
|
143
|
-
if (!frame)
|
|
144
|
-
return;
|
|
138
|
+
if (!frame) return;
|
|
145
139
|
for (const barrier of this._signalBarriers)
|
|
146
140
|
barrier.addFrameNavigation(frame);
|
|
147
141
|
if (frame.pendingDocument() && frame.pendingDocument().documentId === documentId) {
|
|
148
142
|
return;
|
|
149
143
|
}
|
|
150
|
-
const request = documentId ? Array.from(frame._inflightRequests).find(
|
|
144
|
+
const request = documentId ? Array.from(frame._inflightRequests).find(
|
|
145
|
+
(request2) => request2._documentId === documentId
|
|
146
|
+
) : void 0;
|
|
151
147
|
frame.setPendingDocument({ documentId, request });
|
|
152
148
|
}
|
|
153
149
|
frameCommittedNewDocumentNavigation(frameId, url, name, documentId, initial) {
|
|
@@ -173,7 +169,12 @@ class FrameManager {
|
|
|
173
169
|
frame._currentDocument = { documentId, request: void 0 };
|
|
174
170
|
}
|
|
175
171
|
frame._onClearLifecycle();
|
|
176
|
-
const navigationEvent = {
|
|
172
|
+
const navigationEvent = {
|
|
173
|
+
url,
|
|
174
|
+
name,
|
|
175
|
+
newDocument: frame._currentDocument,
|
|
176
|
+
isPublic: true
|
|
177
|
+
};
|
|
177
178
|
this._fireInternalFrameNavigation(frame, navigationEvent);
|
|
178
179
|
if (!initial) {
|
|
179
180
|
import_debugLogger.debugLogger.log("api", ` navigated to "${url}"`);
|
|
@@ -183,21 +184,23 @@ class FrameManager {
|
|
|
183
184
|
}
|
|
184
185
|
frameCommittedSameDocumentNavigation(frameId, url) {
|
|
185
186
|
const frame = this._frames.get(frameId);
|
|
186
|
-
if (!frame)
|
|
187
|
-
return;
|
|
187
|
+
if (!frame) return;
|
|
188
188
|
const pending = frame.pendingDocument();
|
|
189
189
|
if (pending && pending.documentId === void 0 && pending.request === void 0) {
|
|
190
190
|
frame.setPendingDocument(void 0);
|
|
191
191
|
}
|
|
192
192
|
frame._url = url;
|
|
193
|
-
const navigationEvent = {
|
|
193
|
+
const navigationEvent = {
|
|
194
|
+
url,
|
|
195
|
+
name: frame._name,
|
|
196
|
+
isPublic: true
|
|
197
|
+
};
|
|
194
198
|
this._fireInternalFrameNavigation(frame, navigationEvent);
|
|
195
199
|
import_debugLogger.debugLogger.log("api", ` navigated to "${url}"`);
|
|
196
200
|
}
|
|
197
201
|
frameAbortedNavigation(frameId, errorText, documentId) {
|
|
198
202
|
const frame = this._frames.get(frameId);
|
|
199
|
-
if (!frame || !frame.pendingDocument())
|
|
200
|
-
return;
|
|
203
|
+
if (!frame || !frame.pendingDocument()) return;
|
|
201
204
|
if (documentId !== void 0 && frame.pendingDocument().documentId !== documentId)
|
|
202
205
|
return;
|
|
203
206
|
const navigationEvent = {
|
|
@@ -219,8 +222,7 @@ class FrameManager {
|
|
|
219
222
|
}
|
|
220
223
|
frameLifecycleEvent(frameId, event) {
|
|
221
224
|
const frame = this._frames.get(frameId);
|
|
222
|
-
if (frame)
|
|
223
|
-
frame._onLifecycleEvent(event);
|
|
225
|
+
if (frame) frame._onLifecycleEvent(event);
|
|
224
226
|
}
|
|
225
227
|
requestStarted(request, route) {
|
|
226
228
|
const frame = request.frame();
|
|
@@ -235,30 +237,36 @@ class FrameManager {
|
|
|
235
237
|
this._page.addNetworkRequest(request);
|
|
236
238
|
this._page.emitOnContext(import_browserContext.BrowserContext.Events.Request, request);
|
|
237
239
|
if (route)
|
|
238
|
-
new network.Route(request, route).handle([
|
|
240
|
+
new network.Route(request, route).handle([
|
|
241
|
+
...this._page.requestInterceptors,
|
|
242
|
+
...this._page.browserContext.requestInterceptors
|
|
243
|
+
]);
|
|
239
244
|
}
|
|
240
245
|
requestReceivedResponse(response) {
|
|
241
|
-
if (response.request()._isFavicon)
|
|
242
|
-
return;
|
|
246
|
+
if (response.request()._isFavicon) return;
|
|
243
247
|
this._page.emitOnContext(import_browserContext.BrowserContext.Events.Response, response);
|
|
244
248
|
}
|
|
245
249
|
reportRequestFinished(request, response) {
|
|
246
250
|
this._inflightRequestFinished(request);
|
|
247
|
-
if (request._isFavicon)
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
if (request._isFavicon) return;
|
|
252
|
+
this._page.emitOnContext(import_browserContext.BrowserContext.Events.RequestFinished, {
|
|
253
|
+
request,
|
|
254
|
+
response
|
|
255
|
+
});
|
|
250
256
|
}
|
|
251
257
|
requestFailed(request, canceled) {
|
|
252
258
|
const frame = request.frame();
|
|
253
259
|
this._inflightRequestFinished(request);
|
|
254
260
|
if (frame.pendingDocument() && frame.pendingDocument().request === request) {
|
|
255
261
|
let errorText = request.failure().errorText;
|
|
256
|
-
if (canceled)
|
|
257
|
-
|
|
258
|
-
|
|
262
|
+
if (canceled) errorText += "; maybe frame was detached?";
|
|
263
|
+
this.frameAbortedNavigation(
|
|
264
|
+
frame._id,
|
|
265
|
+
errorText,
|
|
266
|
+
frame.pendingDocument().documentId
|
|
267
|
+
);
|
|
259
268
|
}
|
|
260
|
-
if (request._isFavicon)
|
|
261
|
-
return;
|
|
269
|
+
if (request._isFavicon) return;
|
|
262
270
|
this._page.emitOnContext(import_browserContext.BrowserContext.Events.RequestFailed, request);
|
|
263
271
|
}
|
|
264
272
|
removeChildFramesRecursively(frame) {
|
|
@@ -274,36 +282,28 @@ class FrameManager {
|
|
|
274
282
|
}
|
|
275
283
|
_inflightRequestFinished(request) {
|
|
276
284
|
const frame = request.frame();
|
|
277
|
-
if (request._isFavicon)
|
|
278
|
-
|
|
279
|
-
if (!frame._inflightRequests.has(request))
|
|
280
|
-
return;
|
|
285
|
+
if (request._isFavicon) return;
|
|
286
|
+
if (!frame._inflightRequests.has(request)) return;
|
|
281
287
|
frame._inflightRequests.delete(request);
|
|
282
|
-
if (frame._inflightRequests.size === 0)
|
|
283
|
-
frame._startNetworkIdleTimer();
|
|
288
|
+
if (frame._inflightRequests.size === 0) frame._startNetworkIdleTimer();
|
|
284
289
|
}
|
|
285
290
|
_inflightRequestStarted(request) {
|
|
286
291
|
const frame = request.frame();
|
|
287
|
-
if (request._isFavicon)
|
|
288
|
-
return;
|
|
292
|
+
if (request._isFavicon) return;
|
|
289
293
|
frame._inflightRequests.add(request);
|
|
290
|
-
if (frame._inflightRequests.size === 1)
|
|
291
|
-
frame._stopNetworkIdleTimer();
|
|
294
|
+
if (frame._inflightRequests.size === 1) frame._stopNetworkIdleTimer();
|
|
292
295
|
}
|
|
293
296
|
interceptConsoleMessage(message) {
|
|
294
|
-
if (message.type() !== "debug")
|
|
295
|
-
return false;
|
|
297
|
+
if (message.type() !== "debug") return false;
|
|
296
298
|
const tag = message.text();
|
|
297
299
|
const handler = this._consoleMessageTags.get(tag);
|
|
298
|
-
if (!handler)
|
|
299
|
-
return false;
|
|
300
|
+
if (!handler) return false;
|
|
300
301
|
this._consoleMessageTags.delete(tag);
|
|
301
302
|
handler();
|
|
302
303
|
return true;
|
|
303
304
|
}
|
|
304
305
|
clearWebSockets(frame) {
|
|
305
|
-
if (frame.parentFrame())
|
|
306
|
-
return;
|
|
306
|
+
if (frame.parentFrame()) return;
|
|
307
307
|
this._webSockets.clear();
|
|
308
308
|
}
|
|
309
309
|
onWebSocketCreated(requestId, url) {
|
|
@@ -312,36 +312,29 @@ class FrameManager {
|
|
|
312
312
|
}
|
|
313
313
|
onWebSocketRequest(requestId) {
|
|
314
314
|
const ws = this._webSockets.get(requestId);
|
|
315
|
-
if (ws && ws.markAsNotified())
|
|
316
|
-
this._page.emit(import_page.Page.Events.WebSocket, ws);
|
|
315
|
+
if (ws && ws.markAsNotified()) this._page.emit(import_page.Page.Events.WebSocket, ws);
|
|
317
316
|
}
|
|
318
317
|
onWebSocketResponse(requestId, status, statusText) {
|
|
319
318
|
const ws = this._webSockets.get(requestId);
|
|
320
|
-
if (status < 400)
|
|
321
|
-
|
|
322
|
-
if (ws)
|
|
323
|
-
ws.error(`${statusText}: ${status}`);
|
|
319
|
+
if (status < 400) return;
|
|
320
|
+
if (ws) ws.error(`${statusText}: ${status}`);
|
|
324
321
|
}
|
|
325
322
|
onWebSocketFrameSent(requestId, opcode, data) {
|
|
326
323
|
const ws = this._webSockets.get(requestId);
|
|
327
|
-
if (ws)
|
|
328
|
-
ws.frameSent(opcode, data);
|
|
324
|
+
if (ws) ws.frameSent(opcode, data);
|
|
329
325
|
}
|
|
330
326
|
webSocketFrameReceived(requestId, opcode, data) {
|
|
331
327
|
const ws = this._webSockets.get(requestId);
|
|
332
|
-
if (ws)
|
|
333
|
-
ws.frameReceived(opcode, data);
|
|
328
|
+
if (ws) ws.frameReceived(opcode, data);
|
|
334
329
|
}
|
|
335
330
|
webSocketClosed(requestId) {
|
|
336
331
|
const ws = this._webSockets.get(requestId);
|
|
337
|
-
if (ws)
|
|
338
|
-
ws.closed();
|
|
332
|
+
if (ws) ws.closed();
|
|
339
333
|
this._webSockets.delete(requestId);
|
|
340
334
|
}
|
|
341
335
|
webSocketError(requestId, errorMessage) {
|
|
342
336
|
const ws = this._webSockets.get(requestId);
|
|
343
|
-
if (ws)
|
|
344
|
-
ws.error(errorMessage);
|
|
337
|
+
if (ws) ws.error(errorMessage);
|
|
345
338
|
}
|
|
346
339
|
_fireInternalFrameNavigation(frame, event) {
|
|
347
340
|
frame.emit(Frame.Events.InternalNavigation, event);
|
|
@@ -367,15 +360,19 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
367
360
|
this._parentFrame = parentFrame;
|
|
368
361
|
this._currentDocument = { documentId: void 0, request: void 0 };
|
|
369
362
|
this.selectors = new import_frameSelectors.FrameSelectors(this);
|
|
370
|
-
this._contextData.set("main", {
|
|
371
|
-
|
|
363
|
+
this._contextData.set("main", {
|
|
364
|
+
contextPromise: new import_manualPromise.ManualPromise(),
|
|
365
|
+
context: null
|
|
366
|
+
});
|
|
367
|
+
this._contextData.set("utility", {
|
|
368
|
+
contextPromise: new import_manualPromise.ManualPromise(),
|
|
369
|
+
context: null
|
|
370
|
+
});
|
|
372
371
|
this._setContext("main", null);
|
|
373
372
|
this._setContext("utility", null);
|
|
374
|
-
if (this._parentFrame)
|
|
375
|
-
this._parentFrame._childFrames.add(this);
|
|
373
|
+
if (this._parentFrame) this._parentFrame._childFrames.add(this);
|
|
376
374
|
this._firedLifecycleEvents.add("commit");
|
|
377
|
-
if (id !== kDummyFrameId)
|
|
378
|
-
this._startNetworkIdleTimer();
|
|
375
|
+
if (id !== kDummyFrameId) this._startNetworkIdleTimer();
|
|
379
376
|
}
|
|
380
377
|
static {
|
|
381
378
|
this.Events = {
|
|
@@ -388,8 +385,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
388
385
|
return this._detachedScope.isClosed();
|
|
389
386
|
}
|
|
390
387
|
_onLifecycleEvent(event) {
|
|
391
|
-
if (this._firedLifecycleEvents.has(event))
|
|
392
|
-
return;
|
|
388
|
+
if (this._firedLifecycleEvents.has(event)) return;
|
|
393
389
|
this._firedLifecycleEvents.add(event);
|
|
394
390
|
this.emit(Frame.Events.AddLifecycle, event);
|
|
395
391
|
if (this === this._page.mainFrame() && this._url !== "about:blank")
|
|
@@ -400,24 +396,28 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
400
396
|
for (const event of this._firedLifecycleEvents)
|
|
401
397
|
this.emit(Frame.Events.RemoveLifecycle, event);
|
|
402
398
|
this._firedLifecycleEvents.clear();
|
|
403
|
-
this._inflightRequests = new Set(
|
|
399
|
+
this._inflightRequests = new Set(
|
|
400
|
+
Array.from(this._inflightRequests).filter(
|
|
401
|
+
(request) => request === this._currentDocument.request
|
|
402
|
+
)
|
|
403
|
+
);
|
|
404
404
|
this._stopNetworkIdleTimer();
|
|
405
|
-
if (this._inflightRequests.size === 0)
|
|
406
|
-
this._startNetworkIdleTimer();
|
|
405
|
+
if (this._inflightRequests.size === 0) this._startNetworkIdleTimer();
|
|
407
406
|
this._page.mainFrame()._recalculateNetworkIdle(this);
|
|
408
407
|
this._onLifecycleEvent("commit");
|
|
409
408
|
}
|
|
410
409
|
setPendingDocument(documentInfo) {
|
|
411
410
|
this._pendingDocument = documentInfo;
|
|
412
411
|
if (documentInfo)
|
|
413
|
-
this._invalidateNonStallingEvaluations(
|
|
412
|
+
this._invalidateNonStallingEvaluations(
|
|
413
|
+
"Navigation interrupted the evaluation"
|
|
414
|
+
);
|
|
414
415
|
}
|
|
415
416
|
pendingDocument() {
|
|
416
417
|
return this._pendingDocument;
|
|
417
418
|
}
|
|
418
419
|
_invalidateNonStallingEvaluations(message) {
|
|
419
|
-
if (!this._raceAgainstEvaluationStallingEventsPromises.size)
|
|
420
|
-
return;
|
|
420
|
+
if (!this._raceAgainstEvaluationStallingEventsPromises.size) return;
|
|
421
421
|
const error = new Error(message);
|
|
422
422
|
for (const promise of this._raceAgainstEvaluationStallingEventsPromises)
|
|
423
423
|
promise.reject(error);
|
|
@@ -430,10 +430,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
430
430
|
const promise = new import_manualPromise.ManualPromise();
|
|
431
431
|
this._raceAgainstEvaluationStallingEventsPromises.add(promise);
|
|
432
432
|
try {
|
|
433
|
-
return await Promise.race([
|
|
434
|
-
cb(),
|
|
435
|
-
promise
|
|
436
|
-
]);
|
|
433
|
+
return await Promise.race([cb(), promise]);
|
|
437
434
|
} finally {
|
|
438
435
|
this._raceAgainstEvaluationStallingEventsPromises.delete(promise);
|
|
439
436
|
}
|
|
@@ -473,38 +470,54 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
473
470
|
}
|
|
474
471
|
}
|
|
475
472
|
async raceNavigationAction(progress, action) {
|
|
476
|
-
return import_utils.LongStandingScope.raceMultiple(
|
|
477
|
-
this._detachedScope,
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
473
|
+
return import_utils.LongStandingScope.raceMultiple(
|
|
474
|
+
[this._detachedScope, this._page.openScope],
|
|
475
|
+
action().catch((e) => {
|
|
476
|
+
if (e instanceof NavigationAbortedError && e.documentId) {
|
|
477
|
+
const data = this._redirectedNavigations.get(e.documentId);
|
|
478
|
+
if (data) {
|
|
479
|
+
progress.log(`waiting for redirected navigation to "${data.url}"`);
|
|
480
|
+
return progress.race(data.gotoPromise);
|
|
481
|
+
}
|
|
485
482
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
483
|
+
throw e;
|
|
484
|
+
})
|
|
485
|
+
);
|
|
489
486
|
}
|
|
490
487
|
redirectNavigation(url, documentId, referer) {
|
|
491
488
|
const controller = new import_progress.ProgressController();
|
|
492
489
|
const data = {
|
|
493
490
|
url,
|
|
494
|
-
gotoPromise: controller.run(
|
|
491
|
+
gotoPromise: controller.run(
|
|
492
|
+
(progress) => this.gotoImpl(progress, url, { referer }),
|
|
493
|
+
0
|
|
494
|
+
)
|
|
495
495
|
};
|
|
496
496
|
this._redirectedNavigations.set(documentId, data);
|
|
497
|
-
data.gotoPromise.finally(
|
|
497
|
+
data.gotoPromise.finally(
|
|
498
|
+
() => this._redirectedNavigations.delete(documentId)
|
|
499
|
+
);
|
|
498
500
|
}
|
|
499
501
|
async goto(progress, url, options = {}) {
|
|
500
|
-
const constructedNavigationURL = (0, import_utils.constructURLBasedOnBaseURL)(
|
|
501
|
-
|
|
502
|
+
const constructedNavigationURL = (0, import_utils.constructURLBasedOnBaseURL)(
|
|
503
|
+
this._page.browserContext._options.baseURL,
|
|
504
|
+
url
|
|
505
|
+
);
|
|
506
|
+
return this.raceNavigationAction(
|
|
507
|
+
progress,
|
|
508
|
+
async () => this.gotoImpl(progress, constructedNavigationURL, options)
|
|
509
|
+
);
|
|
502
510
|
}
|
|
503
511
|
async gotoImpl(progress, url, options) {
|
|
504
|
-
const waitUntil = verifyLifecycle(
|
|
512
|
+
const waitUntil = verifyLifecycle(
|
|
513
|
+
"waitUntil",
|
|
514
|
+
options.waitUntil === void 0 ? "load" : options.waitUntil
|
|
515
|
+
);
|
|
505
516
|
progress.log(`navigating to "${url}", waiting until "${waitUntil}"`);
|
|
506
517
|
const headers = this._page.extraHTTPHeaders() || [];
|
|
507
|
-
const refererHeader = headers.find(
|
|
518
|
+
const refererHeader = headers.find(
|
|
519
|
+
(h) => h.name.toLowerCase() === "referer"
|
|
520
|
+
);
|
|
508
521
|
let referer = refererHeader ? refererHeader.value : void 0;
|
|
509
522
|
if (options.referer !== void 0) {
|
|
510
523
|
if (referer !== void 0 && referer !== options.referer)
|
|
@@ -524,51 +537,81 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
524
537
|
return event2.newDocument && (event2.newDocument.documentId === navigateResult.newDocumentId || !event2.error);
|
|
525
538
|
};
|
|
526
539
|
const events = navigationEvents.filter(predicate);
|
|
527
|
-
if (events.length)
|
|
528
|
-
event = events[0];
|
|
540
|
+
if (events.length) event = events[0];
|
|
529
541
|
else
|
|
530
|
-
event = await import_helper.helper.waitForEvent(
|
|
542
|
+
event = await import_helper.helper.waitForEvent(
|
|
543
|
+
progress,
|
|
544
|
+
this,
|
|
545
|
+
Frame.Events.InternalNavigation,
|
|
546
|
+
predicate
|
|
547
|
+
).promise;
|
|
531
548
|
if (event.newDocument.documentId !== navigateResult.newDocumentId) {
|
|
532
|
-
throw new NavigationAbortedError(
|
|
549
|
+
throw new NavigationAbortedError(
|
|
550
|
+
navigateResult.newDocumentId,
|
|
551
|
+
`Navigation to "${url}" is interrupted by another navigation to "${event.url}"`
|
|
552
|
+
);
|
|
533
553
|
}
|
|
534
|
-
if (event.error)
|
|
535
|
-
throw event.error;
|
|
554
|
+
if (event.error) throw event.error;
|
|
536
555
|
} else {
|
|
537
556
|
const predicate = (e) => !e.newDocument;
|
|
538
557
|
const events = navigationEvents.filter(predicate);
|
|
539
|
-
if (events.length)
|
|
540
|
-
event = events[0];
|
|
558
|
+
if (events.length) event = events[0];
|
|
541
559
|
else
|
|
542
|
-
event = await import_helper.helper.waitForEvent(
|
|
560
|
+
event = await import_helper.helper.waitForEvent(
|
|
561
|
+
progress,
|
|
562
|
+
this,
|
|
563
|
+
Frame.Events.InternalNavigation,
|
|
564
|
+
predicate
|
|
565
|
+
).promise;
|
|
543
566
|
}
|
|
544
567
|
if (!this._firedLifecycleEvents.has(waitUntil))
|
|
545
|
-
await import_helper.helper.waitForEvent(
|
|
568
|
+
await import_helper.helper.waitForEvent(
|
|
569
|
+
progress,
|
|
570
|
+
this,
|
|
571
|
+
Frame.Events.AddLifecycle,
|
|
572
|
+
(e) => e === waitUntil
|
|
573
|
+
).promise;
|
|
546
574
|
const request = event.newDocument ? event.newDocument.request : void 0;
|
|
547
575
|
const response = request ? progress.race(request._finalRequest().response()) : null;
|
|
548
576
|
return response;
|
|
549
577
|
}
|
|
550
578
|
async _waitForNavigation(progress, requiresNewDocument, options) {
|
|
551
|
-
const waitUntil = verifyLifecycle(
|
|
579
|
+
const waitUntil = verifyLifecycle(
|
|
580
|
+
"waitUntil",
|
|
581
|
+
options.waitUntil === void 0 ? "load" : options.waitUntil
|
|
582
|
+
);
|
|
552
583
|
progress.log(`waiting for navigation until "${waitUntil}"`);
|
|
553
|
-
const navigationEvent = await import_helper.helper.waitForEvent(
|
|
554
|
-
|
|
584
|
+
const navigationEvent = await import_helper.helper.waitForEvent(
|
|
585
|
+
progress,
|
|
586
|
+
this,
|
|
587
|
+
Frame.Events.InternalNavigation,
|
|
588
|
+
(event) => {
|
|
589
|
+
if (event.error) return true;
|
|
590
|
+
if (requiresNewDocument && !event.newDocument) return false;
|
|
591
|
+
progress.log(` navigated to "${this._url}"`);
|
|
555
592
|
return true;
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
return true;
|
|
560
|
-
}).promise;
|
|
561
|
-
if (navigationEvent.error)
|
|
562
|
-
throw navigationEvent.error;
|
|
593
|
+
}
|
|
594
|
+
).promise;
|
|
595
|
+
if (navigationEvent.error) throw navigationEvent.error;
|
|
563
596
|
if (!this._firedLifecycleEvents.has(waitUntil))
|
|
564
|
-
await import_helper.helper.waitForEvent(
|
|
597
|
+
await import_helper.helper.waitForEvent(
|
|
598
|
+
progress,
|
|
599
|
+
this,
|
|
600
|
+
Frame.Events.AddLifecycle,
|
|
601
|
+
(e) => e === waitUntil
|
|
602
|
+
).promise;
|
|
565
603
|
const request = navigationEvent.newDocument ? navigationEvent.newDocument.request : void 0;
|
|
566
604
|
return request ? progress.race(request._finalRequest().response()) : null;
|
|
567
605
|
}
|
|
568
606
|
async _waitForLoadState(progress, state) {
|
|
569
607
|
const waitUntil = verifyLifecycle("state", state);
|
|
570
608
|
if (!this._firedLifecycleEvents.has(waitUntil))
|
|
571
|
-
await import_helper.helper.waitForEvent(
|
|
609
|
+
await import_helper.helper.waitForEvent(
|
|
610
|
+
progress,
|
|
611
|
+
this,
|
|
612
|
+
Frame.Events.AddLifecycle,
|
|
613
|
+
(e) => e === waitUntil
|
|
614
|
+
).promise;
|
|
572
615
|
}
|
|
573
616
|
async frameElement() {
|
|
574
617
|
return this._page.delegate.getFrameElement(this);
|
|
@@ -596,100 +639,170 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
596
639
|
}
|
|
597
640
|
async evaluateExpressionHandle(expression, options = {}, arg) {
|
|
598
641
|
const context = await this._context(options.world ?? "main");
|
|
599
|
-
const value = await context.evaluateExpressionHandle(
|
|
642
|
+
const value = await context.evaluateExpressionHandle(
|
|
643
|
+
expression,
|
|
644
|
+
options,
|
|
645
|
+
arg
|
|
646
|
+
);
|
|
600
647
|
return value;
|
|
601
648
|
}
|
|
602
649
|
async querySelector(selector, options) {
|
|
603
|
-
import_debugLogger.debugLogger.log(
|
|
650
|
+
import_debugLogger.debugLogger.log(
|
|
651
|
+
"api",
|
|
652
|
+
` finding element using the selector "${selector}"`
|
|
653
|
+
);
|
|
604
654
|
return this.selectors.query(selector, options);
|
|
605
655
|
}
|
|
606
656
|
async waitForSelector(progress, selector, performActionPreChecksAndLog, options, scope) {
|
|
607
657
|
if (options.visibility)
|
|
608
|
-
throw new Error(
|
|
658
|
+
throw new Error(
|
|
659
|
+
"options.visibility is not supported, did you mean options.state?"
|
|
660
|
+
);
|
|
609
661
|
if (options.waitFor && options.waitFor !== "visible")
|
|
610
|
-
throw new Error(
|
|
662
|
+
throw new Error(
|
|
663
|
+
"options.waitFor is not supported, did you mean options.state?"
|
|
664
|
+
);
|
|
611
665
|
const { state = "visible" } = options;
|
|
612
666
|
if (!["attached", "detached", "visible", "hidden"].includes(state))
|
|
613
|
-
throw new Error(
|
|
667
|
+
throw new Error(
|
|
668
|
+
`state: expected one of (attached|detached|visible|hidden)`
|
|
669
|
+
);
|
|
614
670
|
if (performActionPreChecksAndLog)
|
|
615
|
-
progress.log(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
671
|
+
progress.log(
|
|
672
|
+
`waiting for ${this._asLocator(selector)}${state === "attached" ? "" : " to be " + state}`
|
|
673
|
+
);
|
|
674
|
+
const promise = this.retryWithProgressAndTimeouts(
|
|
675
|
+
progress,
|
|
676
|
+
[0, 20, 50, 100, 100, 500],
|
|
677
|
+
async (continuePolling) => {
|
|
678
|
+
if (performActionPreChecksAndLog)
|
|
679
|
+
await this._page.performActionPreChecks(progress);
|
|
680
|
+
const resolved = await progress.race(
|
|
681
|
+
this.selectors.resolveInjectedForSelector(selector, options, scope)
|
|
682
|
+
);
|
|
683
|
+
if (!resolved) {
|
|
684
|
+
if (state === "hidden" || state === "detached") return null;
|
|
685
|
+
return continuePolling;
|
|
686
|
+
}
|
|
687
|
+
const result = await progress.race(
|
|
688
|
+
resolved.injected.evaluateHandle(
|
|
689
|
+
(injected, { info, root }) => {
|
|
690
|
+
if (root && !root.isConnected)
|
|
691
|
+
throw injected.createStacklessError(
|
|
692
|
+
"Element is not attached to the DOM"
|
|
693
|
+
);
|
|
694
|
+
const elements = injected.querySelectorAll(
|
|
695
|
+
info.parsed,
|
|
696
|
+
root || document
|
|
697
|
+
);
|
|
698
|
+
const element2 = elements[0];
|
|
699
|
+
const visible2 = element2 ? injected.utils.isElementVisible(element2) : false;
|
|
700
|
+
let log2 = "";
|
|
701
|
+
if (elements.length > 1) {
|
|
702
|
+
if (info.strict)
|
|
703
|
+
throw injected.strictModeViolationError(
|
|
704
|
+
info.parsed,
|
|
705
|
+
elements
|
|
706
|
+
);
|
|
707
|
+
log2 = ` locator resolved to ${elements.length} elements. Proceeding with the first one: ${injected.previewNode(
|
|
708
|
+
elements[0]
|
|
709
|
+
)}`;
|
|
710
|
+
} else if (element2) {
|
|
711
|
+
log2 = ` locator resolved to ${visible2 ? "visible" : "hidden"} ${injected.previewNode(element2)}`;
|
|
712
|
+
}
|
|
713
|
+
return { log: log2, element: element2, visible: visible2, attached: !!element2 };
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
info: resolved.info,
|
|
717
|
+
root: resolved.frame === this ? scope : void 0
|
|
718
|
+
}
|
|
719
|
+
)
|
|
720
|
+
);
|
|
721
|
+
const { log, visible, attached } = await progress.race(
|
|
722
|
+
result.evaluate((r) => ({
|
|
723
|
+
log: r.log,
|
|
724
|
+
visible: r.visible,
|
|
725
|
+
attached: r.attached
|
|
726
|
+
}))
|
|
727
|
+
);
|
|
728
|
+
if (log) progress.log(log);
|
|
729
|
+
const success = {
|
|
730
|
+
attached,
|
|
731
|
+
detached: !attached,
|
|
732
|
+
visible,
|
|
733
|
+
hidden: !visible
|
|
734
|
+
}[state];
|
|
735
|
+
if (!success) {
|
|
736
|
+
result.dispose();
|
|
737
|
+
return continuePolling;
|
|
738
|
+
}
|
|
739
|
+
if (options.omitReturnValue) {
|
|
740
|
+
result.dispose();
|
|
622
741
|
return null;
|
|
623
|
-
return continuePolling;
|
|
624
|
-
}
|
|
625
|
-
const result = await progress.race(resolved.injected.evaluateHandle((injected, { info, root }) => {
|
|
626
|
-
if (root && !root.isConnected)
|
|
627
|
-
throw injected.createStacklessError("Element is not attached to the DOM");
|
|
628
|
-
const elements = injected.querySelectorAll(info.parsed, root || document);
|
|
629
|
-
const element2 = elements[0];
|
|
630
|
-
const visible2 = element2 ? injected.utils.isElementVisible(element2) : false;
|
|
631
|
-
let log2 = "";
|
|
632
|
-
if (elements.length > 1) {
|
|
633
|
-
if (info.strict)
|
|
634
|
-
throw injected.strictModeViolationError(info.parsed, elements);
|
|
635
|
-
log2 = ` locator resolved to ${elements.length} elements. Proceeding with the first one: ${injected.previewNode(elements[0])}`;
|
|
636
|
-
} else if (element2) {
|
|
637
|
-
log2 = ` locator resolved to ${visible2 ? "visible" : "hidden"} ${injected.previewNode(element2)}`;
|
|
638
742
|
}
|
|
639
|
-
|
|
640
|
-
}, { info: resolved.info, root: resolved.frame === this ? scope : void 0 }));
|
|
641
|
-
const { log, visible, attached } = await progress.race(result.evaluate((r) => ({ log: r.log, visible: r.visible, attached: r.attached })));
|
|
642
|
-
if (log)
|
|
643
|
-
progress.log(log);
|
|
644
|
-
const success = { attached, detached: !attached, visible, hidden: !visible }[state];
|
|
645
|
-
if (!success) {
|
|
743
|
+
const element = state === "attached" || state === "visible" ? await progress.race(result.evaluateHandle((r) => r.element)) : null;
|
|
646
744
|
result.dispose();
|
|
647
|
-
return
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
await progress.race(options.__testHookBeforeAdoptNode());
|
|
659
|
-
try {
|
|
660
|
-
const mainContext = await progress.race(resolved.frame._mainContext());
|
|
661
|
-
return await progress.race(element._adoptTo(mainContext));
|
|
662
|
-
} catch (e) {
|
|
663
|
-
return continuePolling;
|
|
745
|
+
if (!element) return null;
|
|
746
|
+
if (options.__testHookBeforeAdoptNode)
|
|
747
|
+
await progress.race(options.__testHookBeforeAdoptNode());
|
|
748
|
+
try {
|
|
749
|
+
const mainContext = await progress.race(
|
|
750
|
+
resolved.frame._mainContext()
|
|
751
|
+
);
|
|
752
|
+
return await progress.race(element._adoptTo(mainContext));
|
|
753
|
+
} catch (e) {
|
|
754
|
+
return continuePolling;
|
|
755
|
+
}
|
|
664
756
|
}
|
|
665
|
-
|
|
757
|
+
);
|
|
666
758
|
return scope ? scope._context._raceAgainstContextDestroyed(promise) : promise;
|
|
667
759
|
}
|
|
668
760
|
async dispatchEvent(progress, selector, type, eventInit = {}, options, scope) {
|
|
669
|
-
await this._callOnElementOnceMatches(
|
|
670
|
-
|
|
671
|
-
|
|
761
|
+
await this._callOnElementOnceMatches(
|
|
762
|
+
progress,
|
|
763
|
+
selector,
|
|
764
|
+
(injectedScript, element, data) => {
|
|
765
|
+
injectedScript.dispatchEvent(element, data.type, data.eventInit);
|
|
766
|
+
},
|
|
767
|
+
{ type, eventInit },
|
|
768
|
+
{ mainWorld: true, ...options },
|
|
769
|
+
scope
|
|
770
|
+
);
|
|
672
771
|
}
|
|
673
772
|
async evalOnSelector(selector, strict, expression, isFunction, arg, scope) {
|
|
674
773
|
const handle = await this.selectors.query(selector, { strict }, scope);
|
|
675
774
|
if (!handle)
|
|
676
775
|
throw new Error(`Failed to find element matching selector "${selector}"`);
|
|
677
|
-
const result = await handle.evaluateExpression(
|
|
776
|
+
const result = await handle.evaluateExpression(
|
|
777
|
+
expression,
|
|
778
|
+
{ isFunction },
|
|
779
|
+
arg
|
|
780
|
+
);
|
|
678
781
|
handle.dispose();
|
|
679
782
|
return result;
|
|
680
783
|
}
|
|
681
784
|
async evalOnSelectorAll(selector, expression, isFunction, arg, scope) {
|
|
682
|
-
const arrayHandle = await this.selectors.queryArrayInMainWorld(
|
|
683
|
-
|
|
785
|
+
const arrayHandle = await this.selectors.queryArrayInMainWorld(
|
|
786
|
+
selector,
|
|
787
|
+
scope
|
|
788
|
+
);
|
|
789
|
+
const result = await arrayHandle.evaluateExpression(
|
|
790
|
+
expression,
|
|
791
|
+
{ isFunction },
|
|
792
|
+
arg
|
|
793
|
+
);
|
|
684
794
|
arrayHandle.dispose();
|
|
685
795
|
return result;
|
|
686
796
|
}
|
|
687
797
|
async maskSelectors(selectors, color) {
|
|
688
798
|
const context = await this._utilityContext();
|
|
689
799
|
const injectedScript = await context.injectedScript();
|
|
690
|
-
await injectedScript.evaluate(
|
|
691
|
-
injected
|
|
692
|
-
|
|
800
|
+
await injectedScript.evaluate(
|
|
801
|
+
(injected, { parsed, color: color2 }) => {
|
|
802
|
+
injected.maskSelectors(parsed, color2);
|
|
803
|
+
},
|
|
804
|
+
{ parsed: selectors, color }
|
|
805
|
+
);
|
|
693
806
|
}
|
|
694
807
|
async querySelectorAll(selector) {
|
|
695
808
|
return this.selectors.queryAll(selector);
|
|
@@ -698,8 +811,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
698
811
|
try {
|
|
699
812
|
return await this.selectors.queryCount(selector, options);
|
|
700
813
|
} catch (e) {
|
|
701
|
-
if (this.isNonRetriableError(e))
|
|
702
|
-
throw e;
|
|
814
|
+
if (this.isNonRetriableError(e)) throw e;
|
|
703
815
|
return 0;
|
|
704
816
|
}
|
|
705
817
|
}
|
|
@@ -715,9 +827,10 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
715
827
|
return retVal;
|
|
716
828
|
});
|
|
717
829
|
} catch (e) {
|
|
718
|
-
if (this.isNonRetriableError(e))
|
|
719
|
-
|
|
720
|
-
|
|
830
|
+
if (this.isNonRetriableError(e)) throw e;
|
|
831
|
+
throw new Error(
|
|
832
|
+
`Unable to retrieve content because the page is navigating and changing the content.`
|
|
833
|
+
);
|
|
721
834
|
}
|
|
722
835
|
}
|
|
723
836
|
async setContent(progress, html, options) {
|
|
@@ -732,12 +845,17 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
732
845
|
tagPromise.resolve();
|
|
733
846
|
});
|
|
734
847
|
const lifecyclePromise = progress.race(tagPromise).then(() => this._waitForLoadState(progress, waitUntil));
|
|
735
|
-
const contentPromise = progress.race(
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
848
|
+
const contentPromise = progress.race(
|
|
849
|
+
context.evaluate(
|
|
850
|
+
({ html: html2, tag: tag2 }) => {
|
|
851
|
+
document.open();
|
|
852
|
+
console.debug(tag2);
|
|
853
|
+
document.write(html2);
|
|
854
|
+
document.close();
|
|
855
|
+
},
|
|
856
|
+
{ html, tag }
|
|
857
|
+
)
|
|
858
|
+
);
|
|
741
859
|
await Promise.all([contentPromise, lifecyclePromise]);
|
|
742
860
|
return null;
|
|
743
861
|
}).finally(() => {
|
|
@@ -751,8 +869,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
751
869
|
return this._url;
|
|
752
870
|
}
|
|
753
871
|
origin() {
|
|
754
|
-
if (!this._url.startsWith("http"))
|
|
755
|
-
return;
|
|
872
|
+
if (!this._url.startsWith("http")) return;
|
|
756
873
|
return network.parseURL(this._url)?.origin;
|
|
757
874
|
}
|
|
758
875
|
parentFrame() {
|
|
@@ -762,18 +879,19 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
762
879
|
return Array.from(this._childFrames);
|
|
763
880
|
}
|
|
764
881
|
async addScriptTag(params) {
|
|
765
|
-
const {
|
|
766
|
-
url = null,
|
|
767
|
-
content = null,
|
|
768
|
-
type = ""
|
|
769
|
-
} = params;
|
|
882
|
+
const { url = null, content = null, type = "" } = params;
|
|
770
883
|
if (!url && !content)
|
|
771
|
-
throw new Error(
|
|
884
|
+
throw new Error(
|
|
885
|
+
"Provide an object with a `url`, `path` or `content` property"
|
|
886
|
+
);
|
|
772
887
|
const context = await this._mainContext();
|
|
773
888
|
return this._raceWithCSPError(async () => {
|
|
774
889
|
if (url !== null)
|
|
775
890
|
return (await context.evaluateHandle(addScriptUrl, { url, type })).asElement();
|
|
776
|
-
const result = (await context.evaluateHandle(addScriptContent, {
|
|
891
|
+
const result = (await context.evaluateHandle(addScriptContent, {
|
|
892
|
+
content,
|
|
893
|
+
type
|
|
894
|
+
})).asElement();
|
|
777
895
|
if (this._page.delegate.cspErrorsAsynchronousForInlineScripts)
|
|
778
896
|
await context.evaluate(() => true);
|
|
779
897
|
return result;
|
|
@@ -781,11 +899,12 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
781
899
|
async function addScriptUrl(params2) {
|
|
782
900
|
const script = document.createElement("script");
|
|
783
901
|
script.src = params2.url;
|
|
784
|
-
if (params2.type)
|
|
785
|
-
script.type = params2.type;
|
|
902
|
+
if (params2.type) script.type = params2.type;
|
|
786
903
|
const promise = new Promise((res, rej) => {
|
|
787
904
|
script.onload = res;
|
|
788
|
-
script.onerror = (e) => rej(
|
|
905
|
+
script.onerror = (e) => rej(
|
|
906
|
+
typeof e === "string" ? new Error(e) : new Error(`Failed to load script at ${script.src}`)
|
|
907
|
+
);
|
|
789
908
|
});
|
|
790
909
|
document.head.appendChild(script);
|
|
791
910
|
await promise;
|
|
@@ -798,18 +917,16 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
798
917
|
let error = null;
|
|
799
918
|
script.onerror = (e) => error = e;
|
|
800
919
|
document.head.appendChild(script);
|
|
801
|
-
if (error)
|
|
802
|
-
throw error;
|
|
920
|
+
if (error) throw error;
|
|
803
921
|
return script;
|
|
804
922
|
}
|
|
805
923
|
}
|
|
806
924
|
async addStyleTag(params) {
|
|
807
|
-
const {
|
|
808
|
-
url = null,
|
|
809
|
-
content = null
|
|
810
|
-
} = params;
|
|
925
|
+
const { url = null, content = null } = params;
|
|
811
926
|
if (!url && !content)
|
|
812
|
-
throw new Error(
|
|
927
|
+
throw new Error(
|
|
928
|
+
"Provide an object with a `url`, `path` or `content` property"
|
|
929
|
+
);
|
|
813
930
|
const context = await this._mainContext();
|
|
814
931
|
return this._raceWithCSPError(async () => {
|
|
815
932
|
if (url !== null)
|
|
@@ -848,21 +965,25 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
848
965
|
let cspMessage;
|
|
849
966
|
const actionPromise = func().then((r) => result = r).catch((e) => error = e);
|
|
850
967
|
const errorPromise = new Promise((resolve) => {
|
|
851
|
-
listeners.push(
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
968
|
+
listeners.push(
|
|
969
|
+
import_eventsHelper.eventsHelper.addEventListener(
|
|
970
|
+
this._page.browserContext,
|
|
971
|
+
import_browserContext.BrowserContext.Events.Console,
|
|
972
|
+
(message) => {
|
|
973
|
+
if (message.page() !== this._page || message.type() !== "error")
|
|
974
|
+
return;
|
|
975
|
+
if (message.text().includes("Content-Security-Policy") || message.text().includes("Content Security Policy")) {
|
|
976
|
+
cspMessage = message;
|
|
977
|
+
resolve();
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
)
|
|
981
|
+
);
|
|
859
982
|
});
|
|
860
983
|
await Promise.race([actionPromise, errorPromise]);
|
|
861
984
|
import_eventsHelper.eventsHelper.removeEventListeners(listeners);
|
|
862
|
-
if (cspMessage)
|
|
863
|
-
|
|
864
|
-
if (error)
|
|
865
|
-
throw error;
|
|
985
|
+
if (cspMessage) throw new Error(cspMessage.text());
|
|
986
|
+
if (error) throw error;
|
|
866
987
|
return result;
|
|
867
988
|
}
|
|
868
989
|
async retryWithProgressAndTimeouts(progress, timeouts, action) {
|
|
@@ -873,32 +994,30 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
873
994
|
const timeout = timeouts[Math.min(timeoutIndex++, timeouts.length - 1)];
|
|
874
995
|
if (timeout) {
|
|
875
996
|
const actionPromise = new Promise((f) => setTimeout(f, timeout));
|
|
876
|
-
await progress.race(
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
997
|
+
await progress.race(
|
|
998
|
+
import_utils.LongStandingScope.raceMultiple(
|
|
999
|
+
[this._page.openScope, this._detachedScope],
|
|
1000
|
+
actionPromise
|
|
1001
|
+
)
|
|
1002
|
+
);
|
|
880
1003
|
}
|
|
881
1004
|
try {
|
|
882
1005
|
const result = await action(continuePolling);
|
|
883
|
-
if (result === continuePolling)
|
|
884
|
-
continue;
|
|
1006
|
+
if (result === continuePolling) continue;
|
|
885
1007
|
return result;
|
|
886
1008
|
} catch (e) {
|
|
887
|
-
if (this.isNonRetriableError(e))
|
|
888
|
-
throw e;
|
|
1009
|
+
if (this.isNonRetriableError(e)) throw e;
|
|
889
1010
|
continue;
|
|
890
1011
|
}
|
|
891
1012
|
}
|
|
892
1013
|
}
|
|
893
1014
|
isNonRetriableError(e) {
|
|
894
|
-
if ((0, import_progress.isAbortError)(e))
|
|
895
|
-
return true;
|
|
1015
|
+
if ((0, import_progress.isAbortError)(e)) return true;
|
|
896
1016
|
if (js.isJavaScriptErrorInEvaluate(e) || (0, import_protocolError.isSessionClosedError)(e))
|
|
897
1017
|
return true;
|
|
898
1018
|
if (dom.isNonRecoverableDOMError(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
|
|
899
1019
|
return true;
|
|
900
|
-
if (this.isDetached())
|
|
901
|
-
return true;
|
|
1020
|
+
if (this.isDetached()) return true;
|
|
902
1021
|
return false;
|
|
903
1022
|
}
|
|
904
1023
|
_shouldAttemptAutoHealing(locatorAutohealOption) {
|
|
@@ -914,9 +1033,10 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
914
1033
|
actionName,
|
|
915
1034
|
error
|
|
916
1035
|
});
|
|
917
|
-
if (!healedSelector)
|
|
918
|
-
|
|
919
|
-
|
|
1036
|
+
if (!healedSelector) return void 0;
|
|
1037
|
+
progress.log(
|
|
1038
|
+
`[Auto-Healing] Retrying with healed selector: ${healedSelector}`
|
|
1039
|
+
);
|
|
920
1040
|
const healingTimeout = (0, import_healingService.getHealingConfig)().timeout;
|
|
921
1041
|
const healingController = new import_progress.ProgressController(progress.metadata);
|
|
922
1042
|
return await healingController.run(async (healingProgress) => {
|
|
@@ -925,123 +1045,252 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
925
1045
|
}
|
|
926
1046
|
async _retryWithProgressIfNotConnectedWithHealing(progress, selector, strict, performActionPreChecks, action, actionName, autoHeal) {
|
|
927
1047
|
try {
|
|
928
|
-
return await this._retryWithProgressIfNotConnected(
|
|
1048
|
+
return await this._retryWithProgressIfNotConnected(
|
|
1049
|
+
progress,
|
|
1050
|
+
selector,
|
|
1051
|
+
strict,
|
|
1052
|
+
performActionPreChecks,
|
|
1053
|
+
action
|
|
1054
|
+
);
|
|
929
1055
|
} catch (error) {
|
|
930
|
-
if (!this._shouldAttemptAutoHealing(autoHeal))
|
|
931
|
-
throw error;
|
|
1056
|
+
if (!this._shouldAttemptAutoHealing(autoHeal)) throw error;
|
|
932
1057
|
const healedResult = await this._attemptHealingRetry(
|
|
933
1058
|
progress,
|
|
934
1059
|
selector,
|
|
935
1060
|
actionName,
|
|
936
1061
|
error,
|
|
937
1062
|
async (healingProgress, healedSelector) => {
|
|
938
|
-
return await this._retryWithProgressIfNotConnected(
|
|
1063
|
+
return await this._retryWithProgressIfNotConnected(
|
|
1064
|
+
healingProgress,
|
|
1065
|
+
healedSelector,
|
|
1066
|
+
strict,
|
|
1067
|
+
performActionPreChecks,
|
|
1068
|
+
action
|
|
1069
|
+
);
|
|
939
1070
|
}
|
|
940
1071
|
);
|
|
941
|
-
if (healedResult !== void 0)
|
|
942
|
-
return healedResult;
|
|
1072
|
+
if (healedResult !== void 0) return healedResult;
|
|
943
1073
|
throw error;
|
|
944
1074
|
}
|
|
945
1075
|
}
|
|
946
1076
|
async _retryWithProgressIfNotConnected(progress, selector, strict, performActionPreChecks, action) {
|
|
947
1077
|
progress.log(`waiting for ${this._asLocator(selector)}`);
|
|
948
|
-
return this.retryWithProgressAndTimeouts(
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1078
|
+
return this.retryWithProgressAndTimeouts(
|
|
1079
|
+
progress,
|
|
1080
|
+
[0, 20, 50, 100, 100, 500],
|
|
1081
|
+
async (continuePolling) => {
|
|
1082
|
+
if (performActionPreChecks)
|
|
1083
|
+
await this._page.performActionPreChecks(progress);
|
|
1084
|
+
const resolved = await progress.race(
|
|
1085
|
+
this.selectors.resolveInjectedForSelector(selector, { strict })
|
|
1086
|
+
);
|
|
1087
|
+
if (!resolved) return continuePolling;
|
|
1088
|
+
const result = await progress.race(
|
|
1089
|
+
resolved.injected.evaluateHandle(
|
|
1090
|
+
(injected, { info, callId }) => {
|
|
1091
|
+
const elements = injected.querySelectorAll(info.parsed, document);
|
|
1092
|
+
if (callId)
|
|
1093
|
+
injected.markTargetElements(new Set(elements), callId);
|
|
1094
|
+
const element2 = elements[0];
|
|
1095
|
+
let log2 = "";
|
|
1096
|
+
if (elements.length > 1) {
|
|
1097
|
+
if (info.strict)
|
|
1098
|
+
throw injected.strictModeViolationError(
|
|
1099
|
+
info.parsed,
|
|
1100
|
+
elements
|
|
1101
|
+
);
|
|
1102
|
+
log2 = ` locator resolved to ${elements.length} elements. Proceeding with the first one: ${injected.previewNode(
|
|
1103
|
+
elements[0]
|
|
1104
|
+
)}`;
|
|
1105
|
+
} else if (element2) {
|
|
1106
|
+
log2 = ` locator resolved to ${injected.previewNode(element2)}`;
|
|
1107
|
+
}
|
|
1108
|
+
return { log: log2, success: !!element2, element: element2 };
|
|
1109
|
+
},
|
|
1110
|
+
{ info: resolved.info, callId: progress.metadata.id }
|
|
1111
|
+
)
|
|
1112
|
+
);
|
|
1113
|
+
const { log, success } = await progress.race(
|
|
1114
|
+
result.evaluate((r) => ({ log: r.log, success: r.success }))
|
|
1115
|
+
);
|
|
1116
|
+
if (log) progress.log(log);
|
|
1117
|
+
if (!success) {
|
|
1118
|
+
result.dispose();
|
|
1119
|
+
return continuePolling;
|
|
966
1120
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
if (log)
|
|
971
|
-
progress.log(log);
|
|
972
|
-
if (!success) {
|
|
1121
|
+
const element = await progress.race(
|
|
1122
|
+
result.evaluateHandle((r) => r.element)
|
|
1123
|
+
);
|
|
973
1124
|
result.dispose();
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1125
|
+
try {
|
|
1126
|
+
const result2 = await action(element, progress);
|
|
1127
|
+
if (result2 === "error:notconnected") {
|
|
1128
|
+
progress.log("element was detached from the DOM, retrying");
|
|
1129
|
+
return continuePolling;
|
|
1130
|
+
}
|
|
1131
|
+
return result2;
|
|
1132
|
+
} finally {
|
|
1133
|
+
element?.dispose();
|
|
983
1134
|
}
|
|
984
|
-
return result2;
|
|
985
|
-
} finally {
|
|
986
|
-
element?.dispose();
|
|
987
1135
|
}
|
|
988
|
-
|
|
1136
|
+
);
|
|
989
1137
|
}
|
|
990
1138
|
async rafrafTimeoutScreenshotElementWithProgress(progress, selector, timeout, options) {
|
|
991
|
-
return await this._retryWithProgressIfNotConnected(
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1139
|
+
return await this._retryWithProgressIfNotConnected(
|
|
1140
|
+
progress,
|
|
1141
|
+
selector,
|
|
1142
|
+
true,
|
|
1143
|
+
true,
|
|
1144
|
+
async (handle) => {
|
|
1145
|
+
await handle._frame.rafrafTimeout(progress, timeout);
|
|
1146
|
+
return await this._page.screenshotter.screenshotElement(
|
|
1147
|
+
progress,
|
|
1148
|
+
handle,
|
|
1149
|
+
options
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
);
|
|
995
1153
|
}
|
|
996
1154
|
async click(progress, selector, options) {
|
|
997
|
-
return dom.assertDone(
|
|
1155
|
+
return dom.assertDone(
|
|
1156
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1157
|
+
progress,
|
|
1158
|
+
selector,
|
|
1159
|
+
options.strict,
|
|
1160
|
+
!options.force,
|
|
1161
|
+
(handle, p) => handle._click(p, { ...options, waitAfter: !options.noWaitAfter }),
|
|
1162
|
+
"click",
|
|
1163
|
+
options.autoHeal
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
998
1166
|
}
|
|
999
1167
|
async dblclick(progress, selector, options) {
|
|
1000
|
-
return dom.assertDone(
|
|
1168
|
+
return dom.assertDone(
|
|
1169
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1170
|
+
progress,
|
|
1171
|
+
selector,
|
|
1172
|
+
options.strict,
|
|
1173
|
+
!options.force,
|
|
1174
|
+
(handle, p) => handle._dblclick(p, options),
|
|
1175
|
+
"dblclick",
|
|
1176
|
+
options.autoHeal
|
|
1177
|
+
)
|
|
1178
|
+
);
|
|
1001
1179
|
}
|
|
1002
1180
|
async dragAndDrop(progress, source, target, options) {
|
|
1003
|
-
dom.assertDone(
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1181
|
+
dom.assertDone(
|
|
1182
|
+
await this._retryWithProgressIfNotConnected(
|
|
1183
|
+
progress,
|
|
1184
|
+
source,
|
|
1185
|
+
options.strict,
|
|
1186
|
+
!options.force,
|
|
1187
|
+
async (handle, p) => {
|
|
1188
|
+
return handle._retryPointerAction(
|
|
1189
|
+
p,
|
|
1190
|
+
"move and down",
|
|
1191
|
+
false,
|
|
1192
|
+
async (point) => {
|
|
1193
|
+
await this._page.mouse.move(p, point.x, point.y);
|
|
1194
|
+
await this._page.mouse.down(p);
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
...options,
|
|
1198
|
+
waitAfter: "disabled",
|
|
1199
|
+
position: options.sourcePosition
|
|
1200
|
+
}
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
)
|
|
1204
|
+
);
|
|
1205
|
+
dom.assertDone(
|
|
1206
|
+
await this._retryWithProgressIfNotConnected(
|
|
1207
|
+
progress,
|
|
1208
|
+
target,
|
|
1209
|
+
options.strict,
|
|
1210
|
+
false,
|
|
1211
|
+
async (handle, p) => {
|
|
1212
|
+
return handle._retryPointerAction(
|
|
1213
|
+
p,
|
|
1214
|
+
"move and up",
|
|
1215
|
+
false,
|
|
1216
|
+
async (point) => {
|
|
1217
|
+
await this._page.mouse.move(p, point.x, point.y);
|
|
1218
|
+
await this._page.mouse.up(p);
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
...options,
|
|
1222
|
+
waitAfter: "disabled",
|
|
1223
|
+
position: options.targetPosition
|
|
1224
|
+
}
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
)
|
|
1228
|
+
);
|
|
1023
1229
|
}
|
|
1024
1230
|
async tap(progress, selector, options) {
|
|
1025
1231
|
if (!this._page.browserContext._options.hasTouch)
|
|
1026
|
-
throw new Error(
|
|
1027
|
-
|
|
1232
|
+
throw new Error(
|
|
1233
|
+
"The page does not support tap. Use hasTouch context option to enable touch support."
|
|
1234
|
+
);
|
|
1235
|
+
return dom.assertDone(
|
|
1236
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1237
|
+
progress,
|
|
1238
|
+
selector,
|
|
1239
|
+
options.strict,
|
|
1240
|
+
!options.force,
|
|
1241
|
+
(handle, p) => handle._tap(p, options),
|
|
1242
|
+
"tap",
|
|
1243
|
+
options.autoHeal
|
|
1244
|
+
)
|
|
1245
|
+
);
|
|
1028
1246
|
}
|
|
1029
1247
|
async fill(progress, selector, value, options) {
|
|
1030
|
-
return dom.assertDone(
|
|
1248
|
+
return dom.assertDone(
|
|
1249
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1250
|
+
progress,
|
|
1251
|
+
selector,
|
|
1252
|
+
options.strict,
|
|
1253
|
+
!options.force,
|
|
1254
|
+
(handle, p) => handle._fill(p, value, options),
|
|
1255
|
+
"fill",
|
|
1256
|
+
options.autoHeal
|
|
1257
|
+
)
|
|
1258
|
+
);
|
|
1031
1259
|
}
|
|
1032
1260
|
async focus(progress, selector, options) {
|
|
1033
|
-
dom.assertDone(
|
|
1261
|
+
dom.assertDone(
|
|
1262
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1263
|
+
progress,
|
|
1264
|
+
selector,
|
|
1265
|
+
options.strict,
|
|
1266
|
+
true,
|
|
1267
|
+
(handle, p) => handle._focus(p),
|
|
1268
|
+
"focus",
|
|
1269
|
+
options.autoHeal
|
|
1270
|
+
)
|
|
1271
|
+
);
|
|
1034
1272
|
}
|
|
1035
1273
|
async blur(progress, selector, options) {
|
|
1036
|
-
dom.assertDone(
|
|
1274
|
+
dom.assertDone(
|
|
1275
|
+
await this._retryWithProgressIfNotConnected(
|
|
1276
|
+
progress,
|
|
1277
|
+
selector,
|
|
1278
|
+
options.strict,
|
|
1279
|
+
true,
|
|
1280
|
+
(handle, p) => handle._blur(p)
|
|
1281
|
+
)
|
|
1282
|
+
);
|
|
1037
1283
|
}
|
|
1038
1284
|
async resolveSelector(progress, selector, options = {}) {
|
|
1039
|
-
const element = await progress.race(
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1285
|
+
const element = await progress.race(
|
|
1286
|
+
this.selectors.query(selector, options)
|
|
1287
|
+
);
|
|
1288
|
+
if (!element) throw new Error(`No element matching ${selector}`);
|
|
1289
|
+
const generated = await progress.race(
|
|
1290
|
+
element.evaluateInUtility(async ([injected, node]) => {
|
|
1291
|
+
return injected.generateSelectorSimple(node);
|
|
1292
|
+
}, {})
|
|
1293
|
+
);
|
|
1045
1294
|
if (!generated)
|
|
1046
1295
|
throw new Error(`Unable to generate locator for ${selector}`);
|
|
1047
1296
|
let frame = element._frame;
|
|
@@ -1049,9 +1298,11 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1049
1298
|
while (frame?.parentFrame()) {
|
|
1050
1299
|
const frameElement = await progress.race(frame.frameElement());
|
|
1051
1300
|
if (frameElement) {
|
|
1052
|
-
const generated2 = await progress.race(
|
|
1053
|
-
|
|
1054
|
-
|
|
1301
|
+
const generated2 = await progress.race(
|
|
1302
|
+
frameElement.evaluateInUtility(async ([injected, node]) => {
|
|
1303
|
+
return injected.generateSelectorSimple(node);
|
|
1304
|
+
}, {})
|
|
1305
|
+
);
|
|
1055
1306
|
frameElement.dispose();
|
|
1056
1307
|
if (generated2 === "error:notconnected" || !generated2)
|
|
1057
1308
|
throw new Error(`Unable to generate locator for ${selector}`);
|
|
@@ -1063,36 +1314,81 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1063
1314
|
return { resolvedSelector };
|
|
1064
1315
|
}
|
|
1065
1316
|
async textContent(progress, selector, options, scope) {
|
|
1066
|
-
return this._callOnElementOnceMatches(
|
|
1317
|
+
return this._callOnElementOnceMatches(
|
|
1318
|
+
progress,
|
|
1319
|
+
selector,
|
|
1320
|
+
(injected, element) => element.textContent,
|
|
1321
|
+
void 0,
|
|
1322
|
+
options,
|
|
1323
|
+
scope
|
|
1324
|
+
);
|
|
1067
1325
|
}
|
|
1068
1326
|
async innerText(progress, selector, options, scope) {
|
|
1069
|
-
return this._callOnElementOnceMatches(
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1327
|
+
return this._callOnElementOnceMatches(
|
|
1328
|
+
progress,
|
|
1329
|
+
selector,
|
|
1330
|
+
(injectedScript, element) => {
|
|
1331
|
+
if (element.namespaceURI !== "http://www.w3.org/1999/xhtml")
|
|
1332
|
+
throw injectedScript.createStacklessError(
|
|
1333
|
+
"Node is not an HTMLElement"
|
|
1334
|
+
);
|
|
1335
|
+
return element.innerText;
|
|
1336
|
+
},
|
|
1337
|
+
void 0,
|
|
1338
|
+
options,
|
|
1339
|
+
scope
|
|
1340
|
+
);
|
|
1074
1341
|
}
|
|
1075
1342
|
async innerHTML(progress, selector, options, scope) {
|
|
1076
|
-
return this._callOnElementOnceMatches(
|
|
1343
|
+
return this._callOnElementOnceMatches(
|
|
1344
|
+
progress,
|
|
1345
|
+
selector,
|
|
1346
|
+
(injected, element) => element.innerHTML,
|
|
1347
|
+
void 0,
|
|
1348
|
+
options,
|
|
1349
|
+
scope
|
|
1350
|
+
);
|
|
1077
1351
|
}
|
|
1078
1352
|
async getAttribute(progress, selector, name, options, scope) {
|
|
1079
|
-
return this._callOnElementOnceMatches(
|
|
1353
|
+
return this._callOnElementOnceMatches(
|
|
1354
|
+
progress,
|
|
1355
|
+
selector,
|
|
1356
|
+
(injected, element, data) => element.getAttribute(data.name),
|
|
1357
|
+
{ name },
|
|
1358
|
+
options,
|
|
1359
|
+
scope
|
|
1360
|
+
);
|
|
1080
1361
|
}
|
|
1081
1362
|
async inputValue(progress, selector, options, scope) {
|
|
1082
|
-
return this._callOnElementOnceMatches(
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1363
|
+
return this._callOnElementOnceMatches(
|
|
1364
|
+
progress,
|
|
1365
|
+
selector,
|
|
1366
|
+
(injectedScript, node) => {
|
|
1367
|
+
const element = injectedScript.retarget(node, "follow-label");
|
|
1368
|
+
if (!element || element.nodeName !== "INPUT" && element.nodeName !== "TEXTAREA" && element.nodeName !== "SELECT")
|
|
1369
|
+
throw injectedScript.createStacklessError(
|
|
1370
|
+
"Node is not an <input>, <textarea> or <select> element"
|
|
1371
|
+
);
|
|
1372
|
+
return element.value;
|
|
1373
|
+
},
|
|
1374
|
+
void 0,
|
|
1375
|
+
options,
|
|
1376
|
+
scope
|
|
1377
|
+
);
|
|
1088
1378
|
}
|
|
1089
1379
|
async highlight(progress, selector) {
|
|
1090
|
-
const resolved = await progress.race(
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1380
|
+
const resolved = await progress.race(
|
|
1381
|
+
this.selectors.resolveInjectedForSelector(selector)
|
|
1382
|
+
);
|
|
1383
|
+
if (!resolved) return;
|
|
1384
|
+
return await progress.race(
|
|
1385
|
+
resolved.injected.evaluate(
|
|
1386
|
+
(injected, { info }) => {
|
|
1387
|
+
return injected.highlight(info.parsed);
|
|
1388
|
+
},
|
|
1389
|
+
{ info: resolved.info }
|
|
1390
|
+
)
|
|
1391
|
+
);
|
|
1096
1392
|
}
|
|
1097
1393
|
async hideHighlight() {
|
|
1098
1394
|
return this.raceAgainstEvaluationStallingEvents(async () => {
|
|
@@ -1104,9 +1400,16 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1104
1400
|
});
|
|
1105
1401
|
}
|
|
1106
1402
|
async _elementState(progress, selector, state, options, scope) {
|
|
1107
|
-
const result = await this._callOnElementOnceMatches(
|
|
1108
|
-
|
|
1109
|
-
|
|
1403
|
+
const result = await this._callOnElementOnceMatches(
|
|
1404
|
+
progress,
|
|
1405
|
+
selector,
|
|
1406
|
+
(injected, element, data) => {
|
|
1407
|
+
return injected.elementState(element, data.state);
|
|
1408
|
+
},
|
|
1409
|
+
{ state },
|
|
1410
|
+
options,
|
|
1411
|
+
scope
|
|
1412
|
+
);
|
|
1110
1413
|
if (result.received === "error:notconnected")
|
|
1111
1414
|
dom.throwElementIsNotAttached();
|
|
1112
1415
|
return result.matches;
|
|
@@ -1117,17 +1420,29 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1117
1420
|
}
|
|
1118
1421
|
async isVisibleInternal(progress, selector, options = {}, scope) {
|
|
1119
1422
|
try {
|
|
1120
|
-
const resolved = await progress.race(
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1423
|
+
const resolved = await progress.race(
|
|
1424
|
+
this.selectors.resolveInjectedForSelector(selector, options, scope)
|
|
1425
|
+
);
|
|
1426
|
+
if (!resolved) return false;
|
|
1427
|
+
return await progress.race(
|
|
1428
|
+
resolved.injected.evaluate(
|
|
1429
|
+
(injected, { info, root }) => {
|
|
1430
|
+
const element = injected.querySelector(
|
|
1431
|
+
info.parsed,
|
|
1432
|
+
root || document,
|
|
1433
|
+
info.strict
|
|
1434
|
+
);
|
|
1435
|
+
const state = element ? injected.elementState(element, "visible") : { matches: false, received: "error:notconnected" };
|
|
1436
|
+
return state.matches;
|
|
1437
|
+
},
|
|
1438
|
+
{
|
|
1439
|
+
info: resolved.info,
|
|
1440
|
+
root: resolved.frame === this ? scope : void 0
|
|
1441
|
+
}
|
|
1442
|
+
)
|
|
1443
|
+
);
|
|
1128
1444
|
} catch (e) {
|
|
1129
|
-
if (this.isNonRetriableError(e))
|
|
1130
|
-
throw e;
|
|
1445
|
+
if (this.isNonRetriableError(e)) throw e;
|
|
1131
1446
|
return false;
|
|
1132
1447
|
}
|
|
1133
1448
|
}
|
|
@@ -1147,65 +1462,155 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1147
1462
|
return this._elementState(progress, selector, "checked", options, scope);
|
|
1148
1463
|
}
|
|
1149
1464
|
async hover(progress, selector, options) {
|
|
1150
|
-
return dom.assertDone(
|
|
1465
|
+
return dom.assertDone(
|
|
1466
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1467
|
+
progress,
|
|
1468
|
+
selector,
|
|
1469
|
+
options.strict,
|
|
1470
|
+
!options.force,
|
|
1471
|
+
(handle, p) => handle._hover(p, options),
|
|
1472
|
+
"hover",
|
|
1473
|
+
options.autoHeal
|
|
1474
|
+
)
|
|
1475
|
+
);
|
|
1151
1476
|
}
|
|
1152
1477
|
async selectOption(progress, selector, elements, values, options) {
|
|
1153
|
-
return await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1478
|
+
return await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1479
|
+
progress,
|
|
1480
|
+
selector,
|
|
1481
|
+
options.strict,
|
|
1482
|
+
!options.force,
|
|
1483
|
+
(handle, p) => handle._selectOption(p, elements, values, options),
|
|
1484
|
+
"selectOption",
|
|
1485
|
+
options.autoHeal
|
|
1486
|
+
);
|
|
1154
1487
|
}
|
|
1155
1488
|
async setInputFiles(progress, selector, params) {
|
|
1156
1489
|
const inputFileItems = await (0, import_fileUploadUtils.prepareFilesForUpload)(this, params);
|
|
1157
|
-
return dom.assertDone(
|
|
1490
|
+
return dom.assertDone(
|
|
1491
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1492
|
+
progress,
|
|
1493
|
+
selector,
|
|
1494
|
+
params.strict,
|
|
1495
|
+
true,
|
|
1496
|
+
(handle, p) => handle._setInputFiles(p, inputFileItems),
|
|
1497
|
+
"setInputFiles",
|
|
1498
|
+
params.autoHeal
|
|
1499
|
+
)
|
|
1500
|
+
);
|
|
1158
1501
|
}
|
|
1159
1502
|
async type(progress, selector, text, options) {
|
|
1160
|
-
return dom.assertDone(
|
|
1503
|
+
return dom.assertDone(
|
|
1504
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1505
|
+
progress,
|
|
1506
|
+
selector,
|
|
1507
|
+
options.strict,
|
|
1508
|
+
true,
|
|
1509
|
+
(handle, p) => handle._type(p, text, options),
|
|
1510
|
+
"type",
|
|
1511
|
+
options.autoHeal
|
|
1512
|
+
)
|
|
1513
|
+
);
|
|
1161
1514
|
}
|
|
1162
1515
|
async press(progress, selector, key, options) {
|
|
1163
|
-
return dom.assertDone(
|
|
1516
|
+
return dom.assertDone(
|
|
1517
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1518
|
+
progress,
|
|
1519
|
+
selector,
|
|
1520
|
+
options.strict,
|
|
1521
|
+
true,
|
|
1522
|
+
(handle, p) => handle._press(p, key, options),
|
|
1523
|
+
"press",
|
|
1524
|
+
options.autoHeal
|
|
1525
|
+
)
|
|
1526
|
+
);
|
|
1164
1527
|
}
|
|
1165
1528
|
async check(progress, selector, options) {
|
|
1166
|
-
return dom.assertDone(
|
|
1529
|
+
return dom.assertDone(
|
|
1530
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1531
|
+
progress,
|
|
1532
|
+
selector,
|
|
1533
|
+
options.strict,
|
|
1534
|
+
!options.force,
|
|
1535
|
+
(handle, p) => handle._setChecked(p, true, options),
|
|
1536
|
+
"check",
|
|
1537
|
+
options.autoHeal
|
|
1538
|
+
)
|
|
1539
|
+
);
|
|
1167
1540
|
}
|
|
1168
1541
|
async uncheck(progress, selector, options) {
|
|
1169
|
-
return dom.assertDone(
|
|
1542
|
+
return dom.assertDone(
|
|
1543
|
+
await this._retryWithProgressIfNotConnectedWithHealing(
|
|
1544
|
+
progress,
|
|
1545
|
+
selector,
|
|
1546
|
+
options.strict,
|
|
1547
|
+
!options.force,
|
|
1548
|
+
(handle, p) => handle._setChecked(p, false, options),
|
|
1549
|
+
"uncheck",
|
|
1550
|
+
options.autoHeal
|
|
1551
|
+
)
|
|
1552
|
+
);
|
|
1170
1553
|
}
|
|
1171
1554
|
async waitForTimeout(progress, timeout) {
|
|
1172
1555
|
return progress.wait(timeout);
|
|
1173
1556
|
}
|
|
1174
1557
|
async ariaSnapshot(progress, selector) {
|
|
1175
|
-
return await this._retryWithProgressIfNotConnected(
|
|
1558
|
+
return await this._retryWithProgressIfNotConnected(
|
|
1559
|
+
progress,
|
|
1560
|
+
selector,
|
|
1561
|
+
true,
|
|
1562
|
+
true,
|
|
1563
|
+
(handle, p) => p.race(handle.ariaSnapshot())
|
|
1564
|
+
);
|
|
1176
1565
|
}
|
|
1177
1566
|
async expect(progress, selector, options, timeout) {
|
|
1178
|
-
progress.log(
|
|
1567
|
+
progress.log(
|
|
1568
|
+
`${(0, import_utils.renderTitleForCall)(progress.metadata)}${timeout ? ` with timeout ${timeout}ms` : ""}`
|
|
1569
|
+
);
|
|
1179
1570
|
const lastIntermediateResult = { isSet: false };
|
|
1180
1571
|
const fixupMetadataError = (result) => {
|
|
1181
1572
|
if (result.matches === options.isNot)
|
|
1182
|
-
progress.metadata.error = {
|
|
1573
|
+
progress.metadata.error = {
|
|
1574
|
+
error: { name: "Expect", message: "Expect failed" }
|
|
1575
|
+
};
|
|
1183
1576
|
};
|
|
1184
1577
|
try {
|
|
1185
|
-
if (selector)
|
|
1186
|
-
progress.log(`waiting for ${this._asLocator(selector)}`);
|
|
1578
|
+
if (selector) progress.log(`waiting for ${this._asLocator(selector)}`);
|
|
1187
1579
|
await this._page.performActionPreChecks(progress);
|
|
1188
1580
|
try {
|
|
1189
|
-
const resultOneShot = await this._expectInternal(
|
|
1190
|
-
|
|
1191
|
-
|
|
1581
|
+
const resultOneShot = await this._expectInternal(
|
|
1582
|
+
progress,
|
|
1583
|
+
selector,
|
|
1584
|
+
options,
|
|
1585
|
+
lastIntermediateResult,
|
|
1586
|
+
true
|
|
1587
|
+
);
|
|
1588
|
+
if (resultOneShot.matches !== options.isNot) return resultOneShot;
|
|
1192
1589
|
} catch (e) {
|
|
1193
|
-
if (this.isNonRetriableError(e))
|
|
1194
|
-
throw e;
|
|
1590
|
+
if (this.isNonRetriableError(e)) throw e;
|
|
1195
1591
|
}
|
|
1196
|
-
const result = await this.retryWithProgressAndTimeouts(
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1592
|
+
const result = await this.retryWithProgressAndTimeouts(
|
|
1593
|
+
progress,
|
|
1594
|
+
[100, 250, 500, 1e3],
|
|
1595
|
+
async (continuePolling) => {
|
|
1596
|
+
await this._page.performActionPreChecks(progress);
|
|
1597
|
+
const { matches, received } = await this._expectInternal(
|
|
1598
|
+
progress,
|
|
1599
|
+
selector,
|
|
1600
|
+
options,
|
|
1601
|
+
lastIntermediateResult,
|
|
1602
|
+
false
|
|
1603
|
+
);
|
|
1604
|
+
if (matches === options.isNot) {
|
|
1605
|
+
return continuePolling;
|
|
1606
|
+
}
|
|
1607
|
+
return { matches, received };
|
|
1201
1608
|
}
|
|
1202
|
-
|
|
1203
|
-
});
|
|
1609
|
+
);
|
|
1204
1610
|
fixupMetadataError(result);
|
|
1205
1611
|
return result;
|
|
1206
1612
|
} catch (e) {
|
|
1207
|
-
if (!this._shouldAttemptAutoHealing(options.autoHeal))
|
|
1208
|
-
throw e;
|
|
1613
|
+
if (!this._shouldAttemptAutoHealing(options.autoHeal)) throw e;
|
|
1209
1614
|
if (selector) {
|
|
1210
1615
|
const actionName = `expect(${options.expression})`;
|
|
1211
1616
|
const healedResult = await this._attemptHealingRetry(
|
|
@@ -1214,13 +1619,20 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1214
1619
|
actionName,
|
|
1215
1620
|
e,
|
|
1216
1621
|
async (healingProgress, healedSelector) => {
|
|
1217
|
-
return await this.expect(
|
|
1622
|
+
return await this.expect(
|
|
1623
|
+
healingProgress,
|
|
1624
|
+
healedSelector,
|
|
1625
|
+
options,
|
|
1626
|
+
timeout
|
|
1627
|
+
);
|
|
1218
1628
|
}
|
|
1219
1629
|
);
|
|
1220
|
-
if (healedResult !== void 0)
|
|
1221
|
-
return healedResult;
|
|
1630
|
+
if (healedResult !== void 0) return healedResult;
|
|
1222
1631
|
}
|
|
1223
|
-
const result = {
|
|
1632
|
+
const result = {
|
|
1633
|
+
matches: options.isNot,
|
|
1634
|
+
log: (0, import_callLog.compressCallLog)(progress.metadata.log)
|
|
1635
|
+
};
|
|
1224
1636
|
if ((0, import_selectorParser.isInvalidSelectorError)(e)) {
|
|
1225
1637
|
result.errorMessage = "Error: " + e.message;
|
|
1226
1638
|
} else if (js.isJavaScriptErrorInEvaluate(e)) {
|
|
@@ -1229,97 +1641,114 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1229
1641
|
result.received = lastIntermediateResult.received;
|
|
1230
1642
|
result.errorMessage = lastIntermediateResult.errorMessage;
|
|
1231
1643
|
}
|
|
1232
|
-
if (e instanceof import_errors.TimeoutError)
|
|
1233
|
-
result.timedOut = true;
|
|
1644
|
+
if (e instanceof import_errors.TimeoutError) result.timedOut = true;
|
|
1234
1645
|
fixupMetadataError(result);
|
|
1235
1646
|
return result;
|
|
1236
1647
|
}
|
|
1237
1648
|
}
|
|
1238
1649
|
async _expectInternal(progress, selector, options, lastIntermediateResult, noAbort) {
|
|
1239
1650
|
const race = (p) => noAbort ? p : progress.race(p);
|
|
1240
|
-
const selectorInFrame = selector ? await race(
|
|
1651
|
+
const selectorInFrame = selector ? await race(
|
|
1652
|
+
this.selectors.resolveFrameForSelector(selector, { strict: true })
|
|
1653
|
+
) : void 0;
|
|
1241
1654
|
const { frame, info } = selectorInFrame || { frame: this, info: void 0 };
|
|
1242
1655
|
const world = options.expression === "to.have.property" ? "main" : info?.world ?? "utility";
|
|
1243
1656
|
const context = await race(frame._context(world));
|
|
1244
1657
|
const injected = await race(context.injectedScript());
|
|
1245
|
-
const { log, matches, received, missingReceived } = await race(
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1658
|
+
const { log, matches, received, missingReceived } = await race(
|
|
1659
|
+
injected.evaluate(
|
|
1660
|
+
async (injected2, { info: info2, options: options2, callId }) => {
|
|
1661
|
+
const elements = info2 ? injected2.querySelectorAll(info2.parsed, document) : [];
|
|
1662
|
+
if (callId) injected2.markTargetElements(new Set(elements), callId);
|
|
1663
|
+
const isArray = options2.expression === "to.have.count" || options2.expression.endsWith(".array");
|
|
1664
|
+
let log2 = "";
|
|
1665
|
+
if (isArray)
|
|
1666
|
+
log2 = ` locator resolved to ${elements.length} element${elements.length === 1 ? "" : "s"}`;
|
|
1667
|
+
else if (elements.length > 1)
|
|
1668
|
+
throw injected2.strictModeViolationError(info2.parsed, elements);
|
|
1669
|
+
else if (elements.length)
|
|
1670
|
+
log2 = ` locator resolved to ${injected2.previewNode(elements[0])}`;
|
|
1671
|
+
return {
|
|
1672
|
+
log: log2,
|
|
1673
|
+
...await injected2.expect(elements[0], options2, elements)
|
|
1674
|
+
};
|
|
1675
|
+
},
|
|
1676
|
+
{ info, options, callId: progress.metadata.id }
|
|
1677
|
+
)
|
|
1678
|
+
);
|
|
1679
|
+
if (log) progress.log(log);
|
|
1261
1680
|
if (matches === options.isNot) {
|
|
1262
1681
|
if (missingReceived)
|
|
1263
1682
|
lastIntermediateResult.errorMessage = "Error: element(s) not found";
|
|
1264
|
-
else
|
|
1265
|
-
lastIntermediateResult.received = received;
|
|
1683
|
+
else lastIntermediateResult.received = received;
|
|
1266
1684
|
lastIntermediateResult.isSet = true;
|
|
1267
1685
|
if (!missingReceived && !Array.isArray(received))
|
|
1268
|
-
progress.log(
|
|
1686
|
+
progress.log(
|
|
1687
|
+
` unexpected value "${renderUnexpectedValue(
|
|
1688
|
+
options.expression,
|
|
1689
|
+
received
|
|
1690
|
+
)}"`
|
|
1691
|
+
);
|
|
1269
1692
|
}
|
|
1270
1693
|
return { matches, received };
|
|
1271
1694
|
}
|
|
1272
1695
|
async waitForFunctionExpression(progress, expression, isFunction, arg, options, world = "main") {
|
|
1273
1696
|
if (typeof options.pollingInterval === "number")
|
|
1274
|
-
(0, import_utils.assert)(
|
|
1697
|
+
(0, import_utils.assert)(
|
|
1698
|
+
options.pollingInterval > 0,
|
|
1699
|
+
"Cannot poll with non-positive interval: " + options.pollingInterval
|
|
1700
|
+
);
|
|
1275
1701
|
expression = js.normalizeEvaluationExpression(expression, isFunction);
|
|
1276
1702
|
return this.retryWithProgressAndTimeouts(progress, [100], async () => {
|
|
1277
1703
|
const context = world === "main" ? await progress.race(this._mainContext()) : await progress.race(this._utilityContext());
|
|
1278
1704
|
const injectedScript = await progress.race(context.injectedScript());
|
|
1279
|
-
const handle = await progress.race(
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1705
|
+
const handle = await progress.race(
|
|
1706
|
+
injectedScript.evaluateHandle(
|
|
1707
|
+
(injected, { expression: expression2, isFunction: isFunction2, polling, arg: arg2 }) => {
|
|
1708
|
+
let evaledExpression;
|
|
1709
|
+
const predicate = () => {
|
|
1710
|
+
let result2 = evaledExpression ?? globalThis.eval(expression2);
|
|
1711
|
+
if (isFunction2 === true) {
|
|
1712
|
+
evaledExpression = result2;
|
|
1713
|
+
result2 = result2(arg2);
|
|
1714
|
+
} else if (isFunction2 === false) {
|
|
1715
|
+
result2 = result2;
|
|
1716
|
+
} else {
|
|
1717
|
+
if (typeof result2 === "function") {
|
|
1718
|
+
evaledExpression = result2;
|
|
1719
|
+
result2 = result2(arg2);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
return result2;
|
|
1723
|
+
};
|
|
1724
|
+
let fulfill;
|
|
1725
|
+
let reject;
|
|
1726
|
+
let aborted = false;
|
|
1727
|
+
const result = new Promise((f, r) => {
|
|
1728
|
+
fulfill = f;
|
|
1729
|
+
reject = r;
|
|
1730
|
+
});
|
|
1731
|
+
const next = () => {
|
|
1732
|
+
if (aborted) return;
|
|
1733
|
+
try {
|
|
1734
|
+
const success = predicate();
|
|
1735
|
+
if (success) {
|
|
1736
|
+
fulfill(success);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
if (typeof polling !== "number")
|
|
1740
|
+
injected.utils.builtins.requestAnimationFrame(next);
|
|
1741
|
+
else injected.utils.builtins.setTimeout(next, polling);
|
|
1742
|
+
} catch (e) {
|
|
1743
|
+
reject(e);
|
|
1744
|
+
}
|
|
1745
|
+
};
|
|
1746
|
+
next();
|
|
1747
|
+
return { result, abort: () => aborted = true };
|
|
1748
|
+
},
|
|
1749
|
+
{ expression, isFunction, polling: options.pollingInterval, arg }
|
|
1750
|
+
)
|
|
1751
|
+
);
|
|
1323
1752
|
try {
|
|
1324
1753
|
return await progress.race(handle.evaluateHandle((h) => h.result));
|
|
1325
1754
|
} catch (error) {
|
|
@@ -1338,7 +1767,14 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1338
1767
|
return result;
|
|
1339
1768
|
return JSON.stringify(result);
|
|
1340
1769
|
}`;
|
|
1341
|
-
const handle = await this.waitForFunctionExpression(
|
|
1770
|
+
const handle = await this.waitForFunctionExpression(
|
|
1771
|
+
progress,
|
|
1772
|
+
expression,
|
|
1773
|
+
true,
|
|
1774
|
+
void 0,
|
|
1775
|
+
{},
|
|
1776
|
+
"utility"
|
|
1777
|
+
);
|
|
1342
1778
|
return JSON.parse(handle.rawValue());
|
|
1343
1779
|
}
|
|
1344
1780
|
async title() {
|
|
@@ -1346,16 +1782,19 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1346
1782
|
return context.evaluate(() => document.title);
|
|
1347
1783
|
}
|
|
1348
1784
|
async rafrafTimeout(progress, timeout) {
|
|
1349
|
-
if (timeout === 0)
|
|
1350
|
-
return;
|
|
1785
|
+
if (timeout === 0) return;
|
|
1351
1786
|
const context = await progress.race(this._utilityContext());
|
|
1352
1787
|
await Promise.all([
|
|
1353
1788
|
// wait for double raf
|
|
1354
|
-
progress.race(
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1789
|
+
progress.race(
|
|
1790
|
+
context.evaluate(
|
|
1791
|
+
() => new Promise((x) => {
|
|
1792
|
+
requestAnimationFrame(() => {
|
|
1793
|
+
requestAnimationFrame(x);
|
|
1794
|
+
});
|
|
1795
|
+
})
|
|
1796
|
+
)
|
|
1797
|
+
),
|
|
1359
1798
|
progress.wait(timeout)
|
|
1360
1799
|
]);
|
|
1361
1800
|
}
|
|
@@ -1363,62 +1802,83 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1363
1802
|
this._stopNetworkIdleTimer();
|
|
1364
1803
|
this._detachedScope.close(new Error("Frame was detached"));
|
|
1365
1804
|
for (const data of this._contextData.values()) {
|
|
1366
|
-
if (data.context)
|
|
1367
|
-
data.context.contextDestroyed("Frame was detached");
|
|
1805
|
+
if (data.context) data.context.contextDestroyed("Frame was detached");
|
|
1368
1806
|
data.contextPromise.resolve({ destroyedReason: "Frame was detached" });
|
|
1369
1807
|
}
|
|
1370
|
-
if (this._parentFrame)
|
|
1371
|
-
this._parentFrame._childFrames.delete(this);
|
|
1808
|
+
if (this._parentFrame) this._parentFrame._childFrames.delete(this);
|
|
1372
1809
|
this._parentFrame = null;
|
|
1373
1810
|
}
|
|
1374
1811
|
async _callOnElementOnceMatches(progress, selector, body, taskData, options, scope) {
|
|
1375
1812
|
const callbackText = body.toString();
|
|
1376
1813
|
progress.log(`waiting for ${this._asLocator(selector)}`);
|
|
1377
|
-
const promise = this.retryWithProgressAndTimeouts(
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
if (!
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1814
|
+
const promise = this.retryWithProgressAndTimeouts(
|
|
1815
|
+
progress,
|
|
1816
|
+
[0, 20, 50, 100, 100, 500],
|
|
1817
|
+
async (continuePolling) => {
|
|
1818
|
+
const resolved = await progress.race(
|
|
1819
|
+
this.selectors.resolveInjectedForSelector(selector, options, scope)
|
|
1820
|
+
);
|
|
1821
|
+
if (!resolved) return continuePolling;
|
|
1822
|
+
const { log, success, value } = await progress.race(
|
|
1823
|
+
resolved.injected.evaluate(
|
|
1824
|
+
(injected, { info, callbackText: callbackText2, taskData: taskData2, callId, root }) => {
|
|
1825
|
+
const callback = injected.eval(callbackText2);
|
|
1826
|
+
const element = injected.querySelector(
|
|
1827
|
+
info.parsed,
|
|
1828
|
+
root || document,
|
|
1829
|
+
info.strict
|
|
1830
|
+
);
|
|
1831
|
+
if (!element) return { success: false };
|
|
1832
|
+
const log2 = ` locator resolved to ${injected.previewNode(
|
|
1833
|
+
element
|
|
1834
|
+
)}`;
|
|
1835
|
+
if (callId)
|
|
1836
|
+
injected.markTargetElements(/* @__PURE__ */ new Set([element]), callId);
|
|
1837
|
+
return {
|
|
1838
|
+
log: log2,
|
|
1839
|
+
success: true,
|
|
1840
|
+
value: callback(injected, element, taskData2)
|
|
1841
|
+
};
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
info: resolved.info,
|
|
1845
|
+
callbackText,
|
|
1846
|
+
taskData,
|
|
1847
|
+
callId: progress.metadata.id,
|
|
1848
|
+
root: resolved.frame === this ? scope : void 0
|
|
1849
|
+
}
|
|
1850
|
+
)
|
|
1851
|
+
);
|
|
1852
|
+
if (log) progress.log(log);
|
|
1853
|
+
if (!success) return continuePolling;
|
|
1854
|
+
return value;
|
|
1855
|
+
}
|
|
1856
|
+
);
|
|
1397
1857
|
return scope ? scope._context._raceAgainstContextDestroyed(promise) : promise;
|
|
1398
1858
|
}
|
|
1399
1859
|
_setContext(world, context) {
|
|
1400
1860
|
const data = this._contextData.get(world);
|
|
1401
1861
|
data.context = context;
|
|
1402
|
-
if (context)
|
|
1403
|
-
|
|
1404
|
-
else
|
|
1405
|
-
data.contextPromise = new import_manualPromise.ManualPromise();
|
|
1862
|
+
if (context) data.contextPromise.resolve(context);
|
|
1863
|
+
else data.contextPromise = new import_manualPromise.ManualPromise();
|
|
1406
1864
|
}
|
|
1407
1865
|
_contextCreated(world, context) {
|
|
1408
1866
|
const data = this._contextData.get(world);
|
|
1409
1867
|
if (data.context) {
|
|
1410
|
-
data.context.contextDestroyed(
|
|
1868
|
+
data.context.contextDestroyed(
|
|
1869
|
+
"Execution context was destroyed, most likely because of a navigation"
|
|
1870
|
+
);
|
|
1411
1871
|
this._setContext(world, null);
|
|
1412
1872
|
}
|
|
1413
1873
|
this._setContext(world, context);
|
|
1414
1874
|
}
|
|
1415
1875
|
_contextDestroyed(context) {
|
|
1416
|
-
if (this._detachedScope.isClosed())
|
|
1417
|
-
|
|
1418
|
-
|
|
1876
|
+
if (this._detachedScope.isClosed()) return;
|
|
1877
|
+
context.contextDestroyed(
|
|
1878
|
+
"Execution context was destroyed, most likely because of a navigation"
|
|
1879
|
+
);
|
|
1419
1880
|
for (const [world, data] of this._contextData) {
|
|
1420
|
-
if (data.context === context)
|
|
1421
|
-
this._setContext(world, null);
|
|
1881
|
+
if (data.context === context) this._setContext(world, null);
|
|
1422
1882
|
}
|
|
1423
1883
|
}
|
|
1424
1884
|
_startNetworkIdleTimer() {
|
|
@@ -1431,20 +1891,25 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1431
1891
|
}, 500);
|
|
1432
1892
|
}
|
|
1433
1893
|
_stopNetworkIdleTimer() {
|
|
1434
|
-
if (this._networkIdleTimer)
|
|
1435
|
-
clearTimeout(this._networkIdleTimer);
|
|
1894
|
+
if (this._networkIdleTimer) clearTimeout(this._networkIdleTimer);
|
|
1436
1895
|
this._networkIdleTimer = void 0;
|
|
1437
1896
|
this._firedNetworkIdleSelf = false;
|
|
1438
1897
|
}
|
|
1439
1898
|
async extendInjectedScript(source, arg) {
|
|
1440
1899
|
const context = await this._context("main");
|
|
1441
1900
|
const injectedScriptHandle = await context.injectedScript();
|
|
1442
|
-
await injectedScriptHandle.evaluate(
|
|
1443
|
-
injectedScript
|
|
1444
|
-
|
|
1901
|
+
await injectedScriptHandle.evaluate(
|
|
1902
|
+
(injectedScript, { source: source2, arg: arg2 }) => {
|
|
1903
|
+
injectedScript.extend(source2, arg2);
|
|
1904
|
+
},
|
|
1905
|
+
{ source, arg }
|
|
1906
|
+
);
|
|
1445
1907
|
}
|
|
1446
1908
|
_asLocator(selector) {
|
|
1447
|
-
return (0, import_utils.asLocator)(
|
|
1909
|
+
return (0, import_utils.asLocator)(
|
|
1910
|
+
this._page.browserContext._browser.sdkLanguage(),
|
|
1911
|
+
selector
|
|
1912
|
+
);
|
|
1448
1913
|
}
|
|
1449
1914
|
}
|
|
1450
1915
|
class SignalBarrier {
|
|
@@ -1459,20 +1924,23 @@ class SignalBarrier {
|
|
|
1459
1924
|
return this._progress.race(this._promise);
|
|
1460
1925
|
}
|
|
1461
1926
|
addFrameNavigation(frame) {
|
|
1462
|
-
if (frame.parentFrame())
|
|
1463
|
-
return;
|
|
1927
|
+
if (frame.parentFrame()) return;
|
|
1464
1928
|
this.retain();
|
|
1465
|
-
const waiter = import_helper.helper.waitForEvent(
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1929
|
+
const waiter = import_helper.helper.waitForEvent(
|
|
1930
|
+
this._progress,
|
|
1931
|
+
frame,
|
|
1932
|
+
Frame.Events.InternalNavigation,
|
|
1933
|
+
(e) => {
|
|
1934
|
+
if (!e.isPublic) return false;
|
|
1935
|
+
if (!e.error && this._progress)
|
|
1936
|
+
this._progress.log(` navigated to "${frame._url}"`);
|
|
1937
|
+
return true;
|
|
1938
|
+
}
|
|
1939
|
+
);
|
|
1940
|
+
import_utils.LongStandingScope.raceMultiple(
|
|
1941
|
+
[frame._page.openScope, frame._detachedScope],
|
|
1942
|
+
waiter.promise
|
|
1943
|
+
).catch(() => {
|
|
1476
1944
|
}).finally(() => {
|
|
1477
1945
|
waiter.dispose();
|
|
1478
1946
|
this.release();
|
|
@@ -1483,20 +1951,19 @@ class SignalBarrier {
|
|
|
1483
1951
|
}
|
|
1484
1952
|
release() {
|
|
1485
1953
|
--this._protectCount;
|
|
1486
|
-
if (!this._protectCount)
|
|
1487
|
-
this._promise.resolve();
|
|
1954
|
+
if (!this._protectCount) this._promise.resolve();
|
|
1488
1955
|
}
|
|
1489
1956
|
}
|
|
1490
1957
|
function verifyLifecycle(name, waitUntil) {
|
|
1491
|
-
if (waitUntil === "networkidle0")
|
|
1492
|
-
waitUntil = "networkidle";
|
|
1958
|
+
if (waitUntil === "networkidle0") waitUntil = "networkidle";
|
|
1493
1959
|
if (!types.kLifecycleEvents.has(waitUntil))
|
|
1494
|
-
throw new Error(
|
|
1960
|
+
throw new Error(
|
|
1961
|
+
`${name}: expected one of (load|domcontentloaded|networkidle|commit)`
|
|
1962
|
+
);
|
|
1495
1963
|
return waitUntil;
|
|
1496
1964
|
}
|
|
1497
1965
|
function renderUnexpectedValue(expression, received) {
|
|
1498
|
-
if (expression === "to.match.aria")
|
|
1499
|
-
return received ? received.raw : received;
|
|
1966
|
+
if (expression === "to.match.aria") return received ? received.raw : received;
|
|
1500
1967
|
return received;
|
|
1501
1968
|
}
|
|
1502
1969
|
// Annotate the CommonJS export names for ESM import in node:
|