@checkly/playwright-core 1.41.23 → 1.41.25
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/cli/driver.js +1 -9
- package/lib/cli/program.js +3 -11
- package/lib/client/channelOwner.js +1 -1
- package/lib/client/clientHelper.js +1 -5
- package/lib/client/connection.js +1 -1
- package/lib/client/consoleMessage.js +1 -1
- package/lib/client/electron.js +0 -3
- package/lib/client/events.js +0 -1
- package/lib/client/frame.js +1 -2
- package/lib/client/harRouter.js +1 -7
- package/lib/client/page.js +6 -25
- package/lib/common/debugLogger.js +0 -1
- package/lib/common/socksProxy.js +1 -1
- 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 +1 -1
- package/lib/protocol/validator.js +29 -46
- package/lib/remote/playwrightConnection.js +1 -1
- package/lib/remote/playwrightServer.js +166 -72
- package/lib/server/android/android.js +1 -1
- package/lib/server/browserType.js +2 -2
- package/lib/server/chromium/chromium.js +4 -5
- package/lib/server/chromium/crConnection.js +1 -1
- package/lib/server/chromium/crPage.js +2 -45
- package/lib/server/console.js +3 -1
- package/lib/server/debugController.js +3 -0
- package/lib/server/deviceDescriptorsSource.json +50 -50
- package/lib/server/dispatchers/browserContextDispatcher.js +2 -3
- package/lib/server/dispatchers/dispatcher.js +10 -9
- package/lib/server/dispatchers/electronDispatcher.js +0 -13
- package/lib/server/dispatchers/frameDispatcher.js +6 -0
- package/lib/server/dispatchers/pageDispatcher.js +10 -14
- package/lib/server/dom.js +167 -130
- package/lib/server/electron/electron.js +12 -38
- package/lib/server/electron/loader.js +2 -4
- package/lib/server/firefox/ffAccessibility.js +1 -2
- package/lib/server/firefox/ffConnection.js +1 -1
- package/lib/server/firefox/ffPage.js +1 -1
- package/lib/server/frames.js +20 -39
- package/lib/server/helper.js +1 -1
- package/lib/server/page.js +5 -49
- package/lib/server/pipeTransport.js +1 -1
- package/lib/server/playwright.js +1 -1
- package/lib/server/progress.js +11 -3
- package/lib/server/recorder/csharp.js +1 -1
- package/lib/server/recorder.js +1 -1
- package/lib/server/registry/browserFetcher.js +1 -1
- package/lib/server/registry/dependencies.js +4 -5
- package/lib/server/registry/index.js +30 -48
- package/lib/server/registry/nativeDeps.js +94 -0
- package/lib/server/trace/recorder/snapshotter.js +1 -1
- package/lib/server/trace/recorder/tracing.js +2 -5
- package/lib/server/trace/viewer/traceViewer.js +1 -1
- package/lib/server/transport.js +2 -4
- package/lib/server/webkit/wkConnection.js +1 -1
- package/lib/server/webkit/wkPage.js +2 -2
- package/lib/utils/comparators.js +4 -4
- package/lib/utils/fileUtils.js +0 -4
- package/lib/utils/hostPlatform.js +1 -1
- package/lib/utils/index.js +0 -11
- package/lib/utils/isomorphic/locatorParser.js +4 -6
- package/lib/utils/network.js +0 -33
- package/lib/utils/processLauncher.js +0 -7
- package/lib/vite/htmlReport/index.html +11 -11
- package/lib/vite/traceViewer/assets/codeMirrorModule-2mdjgmqe.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-GJA8DRmd.js +24 -0
- package/lib/vite/traceViewer/assets/wsPort-93o0i57c.js +69 -0
- package/lib/vite/traceViewer/assets/wsPort-qI0zJPR7.js +69 -0
- package/lib/vite/traceViewer/index.LR1HufLs.js +2 -0
- package/lib/vite/traceViewer/index.Ox-CymYJ.js +2 -0
- package/lib/vite/traceViewer/index.html +3 -3
- package/lib/vite/traceViewer/sw.bundle.js +4 -4
- package/lib/vite/traceViewer/uiMode.YGPXSUMv.js +10 -0
- package/lib/vite/traceViewer/uiMode.YYFJGvtV.js +10 -0
- package/lib/vite/traceViewer/uiMode.html +3 -3
- package/package.json +1 -1
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.FrameExecutionContext = exports.ElementHandle = void 0;
|
|
6
|
+
exports.NonRecoverableDOMError = exports.InjectedScriptPollHandler = exports.FrameExecutionContext = exports.ElementHandle = void 0;
|
|
7
7
|
exports.assertDone = assertDone;
|
|
8
8
|
exports.isNonRecoverableDOMError = isNonRecoverableDOMError;
|
|
9
9
|
exports.kUnableToAdoptErrorMessage = void 0;
|
|
@@ -136,6 +136,17 @@ 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
|
+
}
|
|
139
150
|
async ownerFrame() {
|
|
140
151
|
const frameId = await this._page._delegate.getOwnerFrame(this);
|
|
141
152
|
if (!frameId) return null;
|
|
@@ -177,19 +188,25 @@ class ElementHandle extends js.JSHandle {
|
|
|
177
188
|
return await this._page._delegate.scrollRectIntoViewIfNeeded(this, rect);
|
|
178
189
|
}
|
|
179
190
|
async _waitAndScrollIntoViewIfNeeded(progress, waitForVisible) {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
const timeouts = [0, 50, 100, 250];
|
|
192
|
+
while (progress.isRunning()) {
|
|
193
|
+
assertDone(throwRetargetableDOMError(await this._waitForElementStates(progress, waitForVisible ? ['visible', 'stable'] : ['stable'], false /* force */)));
|
|
194
|
+
progress.throwIfAborted(); // Avoid action that has side-effects.
|
|
195
|
+
const result = throwRetargetableDOMError(await this._scrollRectIntoViewIfNeeded());
|
|
196
|
+
if (result === 'error:notvisible') {
|
|
197
|
+
if (!waitForVisible) {
|
|
198
|
+
var _timeouts$shift;
|
|
199
|
+
// Wait for a timeout to avoid retrying too often when not waiting for visible.
|
|
200
|
+
// If we wait for visible, this should be covered by _waitForElementStates instead.
|
|
201
|
+
const timeout = (_timeouts$shift = timeouts.shift()) !== null && _timeouts$shift !== void 0 ? _timeouts$shift : 500;
|
|
202
|
+
progress.log(` element is not displayed, retrying in ${timeout}ms`);
|
|
203
|
+
await new Promise(f => setTimeout(f, timeout));
|
|
204
|
+
}
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
assertDone(result);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
193
210
|
}
|
|
194
211
|
async scrollIntoViewIfNeeded(metadata, options = {}) {
|
|
195
212
|
const controller = new _progress.ProgressController(metadata, this);
|
|
@@ -244,10 +261,25 @@ class ElementHandle extends js.JSHandle {
|
|
|
244
261
|
y: box.y + border.top + offset.y
|
|
245
262
|
};
|
|
246
263
|
}
|
|
247
|
-
async
|
|
264
|
+
async _retryPointerAction(progress, actionName, waitForEnabled, action, options) {
|
|
248
265
|
let retry = 0;
|
|
249
266
|
// We progressively wait longer between retries, up to 500ms.
|
|
250
267
|
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
|
+
}];
|
|
251
283
|
while (progress.isRunning()) {
|
|
252
284
|
if (retry) {
|
|
253
285
|
progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}, attempt #${retry}`);
|
|
@@ -260,8 +292,8 @@ class ElementHandle extends js.JSHandle {
|
|
|
260
292
|
} else {
|
|
261
293
|
progress.log(`attempting ${actionName} action${options.trial ? ' (trial run)' : ''}`);
|
|
262
294
|
}
|
|
263
|
-
|
|
264
|
-
const result = await action
|
|
295
|
+
const forceScrollOptions = scrollOptions[retry % scrollOptions.length];
|
|
296
|
+
const result = await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);
|
|
265
297
|
++retry;
|
|
266
298
|
if (result === 'error:notvisible') {
|
|
267
299
|
if (options.force) throw new NonRecoverableDOMError('Element is not visible');
|
|
@@ -273,47 +305,14 @@ class ElementHandle extends js.JSHandle {
|
|
|
273
305
|
progress.log(' element is outside of the viewport');
|
|
274
306
|
continue;
|
|
275
307
|
}
|
|
276
|
-
if (result === 'error:optionsnotfound') {
|
|
277
|
-
progress.log(' did not find some options');
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
308
|
if (typeof result === 'object' && 'hitTargetDescription' in result) {
|
|
281
309
|
progress.log(` ${result.hitTargetDescription} intercepts pointer events`);
|
|
282
310
|
continue;
|
|
283
311
|
}
|
|
284
|
-
if (typeof result === 'object' && 'missingState' in result) {
|
|
285
|
-
progress.log(` element is not ${result.missingState}`);
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
312
|
return result;
|
|
289
313
|
}
|
|
290
314
|
return 'done';
|
|
291
315
|
}
|
|
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
|
-
}
|
|
317
316
|
async _performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options) {
|
|
318
317
|
const {
|
|
319
318
|
force = false,
|
|
@@ -341,19 +340,8 @@ class ElementHandle extends js.JSHandle {
|
|
|
341
340
|
await doScrollIntoView().catch(() => {});
|
|
342
341
|
}
|
|
343
342
|
if (options.__testHookBeforeStable) await options.__testHookBeforeStable();
|
|
344
|
-
|
|
345
|
-
|
|
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
|
-
}
|
|
343
|
+
const result = await this._waitForElementStates(progress, waitForEnabled ? ['visible', 'enabled', 'stable'] : ['visible', 'stable'], force);
|
|
344
|
+
if (result !== 'done') return result;
|
|
357
345
|
if (options.__testHookAfterStable) await options.__testHookAfterStable();
|
|
358
346
|
progress.log(' scrolling into view if needed');
|
|
359
347
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
|
@@ -366,9 +354,7 @@ class ElementHandle extends js.JSHandle {
|
|
|
366
354
|
progress.metadata.point = point;
|
|
367
355
|
await progress.beforeInputAction(this);
|
|
368
356
|
let hitTargetInterceptionHandle;
|
|
369
|
-
if (force) {
|
|
370
|
-
progress.log(` forcing action`);
|
|
371
|
-
} else {
|
|
357
|
+
if (!options.force) {
|
|
372
358
|
if (options.__testHookBeforeHitTarget) await options.__testHookBeforeHitTarget();
|
|
373
359
|
const frameCheckResult = await this._checkFrameIsHitTarget(point);
|
|
374
360
|
if (frameCheckResult === 'error:notconnected' || 'hitTargetDescription' in frameCheckResult) return frameCheckResult;
|
|
@@ -476,32 +462,22 @@ class ElementHandle extends js.JSHandle {
|
|
|
476
462
|
}, this._page._timeoutSettings.timeout(options));
|
|
477
463
|
}
|
|
478
464
|
async _selectOption(progress, elements, values, options) {
|
|
479
|
-
|
|
480
|
-
await
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const result = await this.
|
|
465
|
+
const optionsToSelect = [...elements, ...values];
|
|
466
|
+
await progress.beforeInputAction(this);
|
|
467
|
+
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
|
468
|
+
progress.throwIfAborted(); // Avoid action that has side-effects.
|
|
469
|
+
progress.log(' selecting specified option(s)');
|
|
470
|
+
const result = await this.evaluatePoll(progress, ([injected, node, {
|
|
485
471
|
optionsToSelect,
|
|
486
472
|
force
|
|
487
473
|
}]) => {
|
|
488
|
-
|
|
489
|
-
const checkResult = await injected.checkElementStates(node, ['visible', 'enabled']);
|
|
490
|
-
if (checkResult) return checkResult;
|
|
491
|
-
}
|
|
492
|
-
return injected.selectOptions(node, optionsToSelect);
|
|
474
|
+
return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled'], force, injected.selectOptions.bind(injected, optionsToSelect));
|
|
493
475
|
}, {
|
|
494
476
|
optionsToSelect,
|
|
495
477
|
force: options.force
|
|
496
478
|
});
|
|
497
|
-
if (Array.isArray(result)) {
|
|
498
|
-
progress.log(' selected specified option(s)');
|
|
499
|
-
resultingOptions = result;
|
|
500
|
-
return 'done';
|
|
501
|
-
}
|
|
502
479
|
return result;
|
|
503
|
-
}
|
|
504
|
-
return resultingOptions;
|
|
480
|
+
});
|
|
505
481
|
}
|
|
506
482
|
async fill(metadata, value, options = {}) {
|
|
507
483
|
const controller = new _progress.ProgressController(metadata, this);
|
|
@@ -511,51 +487,38 @@ class ElementHandle extends js.JSHandle {
|
|
|
511
487
|
}, this._page._timeoutSettings.timeout(options));
|
|
512
488
|
}
|
|
513
489
|
async _fill(progress, value, options) {
|
|
514
|
-
progress.log(`
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
});
|
|
490
|
+
progress.log(`elementHandle.fill("${value}")`);
|
|
491
|
+
await progress.beforeInputAction(this);
|
|
492
|
+
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
|
493
|
+
progress.log(' waiting for element to be visible, enabled and editable');
|
|
494
|
+
const filled = await this.evaluatePoll(progress, ([injected, node, {
|
|
495
|
+
value,
|
|
496
|
+
force
|
|
497
|
+
}]) => {
|
|
498
|
+
return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled', 'editable'], force, injected.fill.bind(injected, value));
|
|
499
|
+
}, {
|
|
500
|
+
value,
|
|
501
|
+
force: options.force
|
|
502
|
+
});
|
|
503
|
+
progress.throwIfAborted(); // Avoid action that has side-effects.
|
|
504
|
+
if (filled === 'error:notconnected') return filled;
|
|
505
|
+
progress.log(' element is visible, enabled and editable');
|
|
506
|
+
if (filled === 'needsinput') {
|
|
532
507
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
|
533
|
-
if (
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}, 'input');
|
|
540
|
-
}, options);
|
|
508
|
+
if (value) await this._page.keyboard.insertText(value);else await this._page.keyboard.press('Delete');
|
|
509
|
+
} else {
|
|
510
|
+
assertDone(filled);
|
|
511
|
+
}
|
|
512
|
+
return 'done';
|
|
513
|
+
}, 'input');
|
|
541
514
|
}
|
|
542
515
|
async selectText(metadata, options = {}) {
|
|
543
516
|
const controller = new _progress.ProgressController(metadata, this);
|
|
544
517
|
return controller.run(async progress => {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
return
|
|
548
|
-
|
|
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);
|
|
518
|
+
progress.throwIfAborted(); // Avoid action that has side-effects.
|
|
519
|
+
const result = await this.evaluatePoll(progress, ([injected, node, force]) => {
|
|
520
|
+
return injected.waitForElementStatesAndPerformAction(node, ['visible'], force, injected.selectText.bind(injected));
|
|
521
|
+
}, options.force);
|
|
559
522
|
assertDone(throwRetargetableDOMError(result));
|
|
560
523
|
}, this._page._timeoutSettings.timeout(options));
|
|
561
524
|
}
|
|
@@ -706,12 +669,10 @@ class ElementHandle extends js.JSHandle {
|
|
|
706
669
|
async waitForElementState(metadata, state, options = {}) {
|
|
707
670
|
const controller = new _progress.ProgressController(metadata, this);
|
|
708
671
|
return controller.run(async progress => {
|
|
709
|
-
|
|
710
|
-
const result = await this.
|
|
711
|
-
return
|
|
712
|
-
|
|
713
|
-
}, state);
|
|
714
|
-
}, {});
|
|
672
|
+
progress.log(` waiting for element to be ${state}`);
|
|
673
|
+
const result = await this.evaluatePoll(progress, ([injected, node, state]) => {
|
|
674
|
+
return injected.waitForElementStatesAndPerformAction(node, [state], false, () => 'done');
|
|
675
|
+
}, state);
|
|
715
676
|
assertDone(throwRetargetableDOMError(result));
|
|
716
677
|
}, this._page._timeoutSettings.timeout(options));
|
|
717
678
|
}
|
|
@@ -726,6 +687,22 @@ class ElementHandle extends js.JSHandle {
|
|
|
726
687
|
}
|
|
727
688
|
return this;
|
|
728
689
|
}
|
|
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
|
+
}
|
|
729
706
|
async _checkFrameIsHitTarget(point) {
|
|
730
707
|
let frame = this._frame;
|
|
731
708
|
const data = [];
|
|
@@ -774,7 +751,63 @@ class ElementHandle extends js.JSHandle {
|
|
|
774
751
|
};
|
|
775
752
|
}
|
|
776
753
|
}
|
|
754
|
+
|
|
755
|
+
// Handles an InjectedScriptPoll running in injected script:
|
|
756
|
+
// - streams logs into progress;
|
|
757
|
+
// - cancels the poll when progress cancels.
|
|
777
758
|
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;
|
|
778
811
|
function throwRetargetableDOMError(result) {
|
|
779
812
|
if (result === 'error:notconnected') throw new Error('Element is not attached to the DOM');
|
|
780
813
|
return result;
|
|
@@ -805,4 +838,8 @@ function compensateHalfIntegerRoundingError(point) {
|
|
|
805
838
|
const remainderY = point.y - Math.floor(point.y);
|
|
806
839
|
if (remainderY > 0.49 && remainderY < 0.51) point.y -= 0.02;
|
|
807
840
|
}
|
|
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
|
+
}
|
|
808
845
|
const kUnableToAdoptErrorMessage = exports.kUnableToAdoptErrorMessage = 'Unable to adopt element handle from a different document';
|
|
@@ -20,10 +20,8 @@ var _progress = require("../progress");
|
|
|
20
20
|
var _helper = require("../helper");
|
|
21
21
|
var _eventsHelper = require("../../utils/eventsHelper");
|
|
22
22
|
var readline = _interopRequireWildcard(require("readline"));
|
|
23
|
-
var _debugLogger = require("../../
|
|
23
|
+
var _debugLogger = require("../../common/debugLogger");
|
|
24
24
|
var _instrumentation = require("../instrumentation");
|
|
25
|
-
var _crProtocolHelper = require("../chromium/crProtocolHelper");
|
|
26
|
-
var _console = require("../console");
|
|
27
25
|
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); }
|
|
28
26
|
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; }
|
|
29
27
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -56,6 +54,10 @@ class ElectronApplication extends _instrumentation.SdkObject {
|
|
|
56
54
|
this._process = void 0;
|
|
57
55
|
this._process = process;
|
|
58
56
|
this._browserContext = browser._defaultContext;
|
|
57
|
+
this._browserContext.on(_browserContext.BrowserContext.Events.Close, () => {
|
|
58
|
+
// Emit application closed after context closed.
|
|
59
|
+
Promise.resolve().then(() => this.emit(ElectronApplication.Events.Close));
|
|
60
|
+
});
|
|
59
61
|
this._nodeConnection = nodeConnection;
|
|
60
62
|
this._nodeSession = nodeConnection.rootSession;
|
|
61
63
|
this._nodeSession.on('Runtime.executionContextCreated', async event => {
|
|
@@ -72,40 +74,14 @@ class ElectronApplication extends _instrumentation.SdkObject {
|
|
|
72
74
|
});
|
|
73
75
|
this._nodeElectronHandlePromise.resolve(new js.JSHandle(this._nodeExecutionContext, 'object', 'ElectronModule', remoteObject.objectId));
|
|
74
76
|
});
|
|
75
|
-
this._nodeSession.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
|
|
76
|
-
const appClosePromise = new Promise(f => this.once(ElectronApplication.Events.Close, f));
|
|
77
77
|
this._browserContext.setCustomCloseHandler(async () => {
|
|
78
78
|
await this._browserContext.stopVideoRecording();
|
|
79
79
|
const electronHandle = await this._nodeElectronHandlePromise;
|
|
80
80
|
await electronHandle.evaluate(({
|
|
81
81
|
app
|
|
82
82
|
}) => app.quit()).catch(() => {});
|
|
83
|
-
this._nodeConnection.close();
|
|
84
|
-
await appClosePromise;
|
|
85
83
|
});
|
|
86
84
|
}
|
|
87
|
-
async _onConsoleAPI(event) {
|
|
88
|
-
if (event.executionContextId === 0) {
|
|
89
|
-
// DevTools protocol stores the last 1000 console messages. These
|
|
90
|
-
// messages are always reported even for removed execution contexts. In
|
|
91
|
-
// this case, they are marked with executionContextId = 0 and are
|
|
92
|
-
// reported upon enabling Runtime agent.
|
|
93
|
-
//
|
|
94
|
-
// Ignore these messages since:
|
|
95
|
-
// - there's no execution context we can use to operate with message
|
|
96
|
-
// arguments
|
|
97
|
-
// - these messages are reported before Playwright clients can subscribe
|
|
98
|
-
// to the 'console'
|
|
99
|
-
// page event.
|
|
100
|
-
//
|
|
101
|
-
// @see https://github.com/GoogleChrome/puppeteer/issues/3865
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
if (!this._nodeExecutionContext) return;
|
|
105
|
-
const args = event.args.map(arg => this._nodeExecutionContext.createHandle(arg));
|
|
106
|
-
const message = new _console.ConsoleMessage(null, event.type, undefined, args, (0, _crProtocolHelper.toConsoleMessageLocation)(event.stackTrace));
|
|
107
|
-
this.emit(ElectronApplication.Events.Console, message);
|
|
108
|
-
}
|
|
109
85
|
async initialize() {
|
|
110
86
|
await this._nodeSession.send('Runtime.enable', {});
|
|
111
87
|
// Delay loading the app until browser is started and the browser targets are configured to auto-attach.
|
|
@@ -120,10 +96,13 @@ class ElectronApplication extends _instrumentation.SdkObject {
|
|
|
120
96
|
return this._browserContext;
|
|
121
97
|
}
|
|
122
98
|
async close() {
|
|
123
|
-
|
|
99
|
+
const progressController = new _progress.ProgressController((0, _instrumentation.serverSideCallMetadata)(), this);
|
|
100
|
+
const closed = progressController.run(progress => _helper.helper.waitForEvent(progress, this, ElectronApplication.Events.Close).promise);
|
|
124
101
|
await this._browserContext.close({
|
|
125
102
|
reason: 'Application exited'
|
|
126
103
|
});
|
|
104
|
+
this._nodeConnection.close();
|
|
105
|
+
await closed;
|
|
127
106
|
}
|
|
128
107
|
async browserWindow(page) {
|
|
129
108
|
// Assume CRPage as Electron is always Chromium.
|
|
@@ -140,8 +119,7 @@ class ElectronApplication extends _instrumentation.SdkObject {
|
|
|
140
119
|
}
|
|
141
120
|
exports.ElectronApplication = ElectronApplication;
|
|
142
121
|
ElectronApplication.Events = {
|
|
143
|
-
Close: 'close'
|
|
144
|
-
Console: 'console'
|
|
122
|
+
Close: 'close'
|
|
145
123
|
};
|
|
146
124
|
class Electron extends _instrumentation.SdkObject {
|
|
147
125
|
constructor(playwright) {
|
|
@@ -155,11 +133,10 @@ class Electron extends _instrumentation.SdkObject {
|
|
|
155
133
|
controller.setLogName('browser');
|
|
156
134
|
return controller.run(async progress => {
|
|
157
135
|
let app = undefined;
|
|
158
|
-
// --remote-debugging-port=0 must be the last playwright's argument, loader.ts relies on it.
|
|
159
136
|
const electronArguments = ['--inspect=0', '--remote-debugging-port=0', ...args];
|
|
160
137
|
if (_os.default.platform() === 'linux') {
|
|
161
138
|
const runningAsRoot = process.geteuid && process.geteuid() === 0;
|
|
162
|
-
if (runningAsRoot && electronArguments.indexOf('--no-sandbox') === -1) electronArguments.
|
|
139
|
+
if (runningAsRoot && electronArguments.indexOf('--no-sandbox') === -1) electronArguments.push('--no-sandbox');
|
|
163
140
|
}
|
|
164
141
|
const artifactsDir = await _fs.default.promises.mkdtemp(ARTIFACTS_FOLDER);
|
|
165
142
|
const browserLogsCollector = new _debugLogger.RecentLogsCollector();
|
|
@@ -206,10 +183,7 @@ class Electron extends _instrumentation.SdkObject {
|
|
|
206
183
|
handleSIGINT: true,
|
|
207
184
|
handleSIGTERM: true,
|
|
208
185
|
handleSIGHUP: true,
|
|
209
|
-
onExit: () => {
|
|
210
|
-
var _app;
|
|
211
|
-
return (_app = app) === null || _app === void 0 ? void 0 : _app.emit(ElectronApplication.Events.Close);
|
|
212
|
-
}
|
|
186
|
+
onExit: () => {}
|
|
213
187
|
});
|
|
214
188
|
const waitForXserverError = new Promise(async (resolve, reject) => {
|
|
215
189
|
waitForLine(progress, launchedProcess, /Unable to open X display/).then(() => reject(new Error(['Unable to open X display!', `================================`, 'Most likely this is because there is no X server available.', "Use 'xvfb-run' on Linux to launch your tests with an emulated display server.", "For example: 'xvfb-run npm run test:e2e'", `================================`, progress.metadata.log].join('\n')))).catch(() => {});
|
|
@@ -23,10 +23,8 @@ const {
|
|
|
23
23
|
chromiumSwitches
|
|
24
24
|
} = require('../chromium/chromiumSwitches');
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
// [Electron, -r, loader.js[, --no-sandbox>], --inspect=0, --remote-debugging-port=0, ...args]
|
|
29
|
-
process.argv.splice(1, process.argv.indexOf('--remote-debugging-port=0'));
|
|
26
|
+
// [Electron, -r, loader.js, --inspect=0, --remote-debugging-port=0, ...args]
|
|
27
|
+
process.argv.splice(1, 4);
|
|
30
28
|
for (const arg of chromiumSwitches) {
|
|
31
29
|
const match = arg.match(/--([^=]*)=?(.*)/);
|
|
32
30
|
app.commandLine.appendSwitch(match[1], match[2]);
|
|
@@ -200,7 +200,7 @@ class FFAXNode {
|
|
|
200
200
|
if (!(numericalProperty in this._payload)) continue;
|
|
201
201
|
node[numericalProperty] = this._payload[numericalProperty];
|
|
202
202
|
}
|
|
203
|
-
const tokenProperties = ['autocomplete', 'haspopup', 'orientation'];
|
|
203
|
+
const tokenProperties = ['autocomplete', 'haspopup', 'invalid', 'orientation'];
|
|
204
204
|
for (const tokenProperty of tokenProperties) {
|
|
205
205
|
const value = this._payload[tokenProperty];
|
|
206
206
|
if (!value || value === 'false') continue;
|
|
@@ -210,7 +210,6 @@ class FFAXNode {
|
|
|
210
210
|
axNode.valueString = this._payload.value;
|
|
211
211
|
if ('checked' in this._payload) axNode.checked = this._payload.checked === true ? 'checked' : this._payload.checked === 'mixed' ? 'mixed' : 'unchecked';
|
|
212
212
|
if ('pressed' in this._payload) axNode.pressed = this._payload.pressed === true ? 'pressed' : 'released';
|
|
213
|
-
if ('invalid' in this._payload) axNode.invalid = this._payload.invalid === true ? 'true' : 'false';
|
|
214
213
|
return axNode;
|
|
215
214
|
}
|
|
216
215
|
}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.kBrowserCloseMessageId = exports.FFSession = exports.FFConnection = exports.ConnectionEvents = void 0;
|
|
7
7
|
var _events = require("events");
|
|
8
|
-
var _debugLogger = require("../../
|
|
8
|
+
var _debugLogger = require("../../common/debugLogger");
|
|
9
9
|
var _helper = require("../helper");
|
|
10
10
|
var _protocolError = require("../protocolError");
|
|
11
11
|
/**
|
|
@@ -14,7 +14,7 @@ var _ffExecutionContext = require("./ffExecutionContext");
|
|
|
14
14
|
var _ffInput = require("./ffInput");
|
|
15
15
|
var _ffNetworkManager = require("./ffNetworkManager");
|
|
16
16
|
var _stackTrace = require("../../utils/stackTrace");
|
|
17
|
-
var _debugLogger = require("../../
|
|
17
|
+
var _debugLogger = require("../../common/debugLogger");
|
|
18
18
|
var _manualPromise = require("../../utils/manualPromise");
|
|
19
19
|
var _browserContext = require("../browserContext");
|
|
20
20
|
var _errors = require("../errors");
|