patchright-core 1.48.2 → 1.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +2 -2
  2. package/ThirdPartyNotices.txt +70 -384
  3. package/bin/reinstall_chrome_beta_linux.sh +10 -8
  4. package/bin/reinstall_chrome_stable_linux.sh +10 -8
  5. package/bin/reinstall_msedge_beta_linux.sh +11 -9
  6. package/bin/reinstall_msedge_dev_linux.sh +11 -9
  7. package/bin/reinstall_msedge_stable_linux.sh +11 -9
  8. package/browsers.json +19 -11
  9. package/lib/cli/program.js +23 -5
  10. package/lib/client/channelOwner.js +2 -2
  11. package/lib/client/locator.js +7 -0
  12. package/lib/client/network.js +5 -0
  13. package/lib/client/page.js +4 -2
  14. package/lib/client/tracing.js +13 -0
  15. package/lib/client/waiter.js +15 -11
  16. package/lib/generated/consoleApiSource.js +1 -1
  17. package/lib/generated/injectedScriptSource.js +1 -1
  18. package/lib/generated/pollingRecorderSource.js +1 -1
  19. package/lib/generated/webSocketMockSource.js +1 -1
  20. package/lib/protocol/validator.js +23 -3
  21. package/lib/server/ariaSnapshot.js +33 -0
  22. package/lib/server/bidi/bidiChromium.js +1 -1
  23. package/lib/server/bidi/bidiConnection.js +0 -2
  24. package/lib/server/bidi/bidiExecutionContext.js +0 -3
  25. package/lib/server/browserType.js +4 -1
  26. package/lib/server/chromium/chromium.js +6 -2
  27. package/lib/server/chromium/crExecutionContext.js +0 -13
  28. package/lib/server/chromium/crNetworkManager.js +1 -1
  29. package/lib/server/chromium/crPage.js +4 -5
  30. package/lib/server/codegen/csharp.js +11 -16
  31. package/lib/server/codegen/java.js +4 -7
  32. package/lib/server/codegen/javascript.js +28 -6
  33. package/lib/server/codegen/python.js +12 -16
  34. package/lib/server/debugController.js +8 -5
  35. package/lib/server/deviceDescriptorsSource.json +127 -127
  36. package/lib/server/dispatchers/androidDispatcher.js +13 -2
  37. package/lib/server/dispatchers/debugControllerDispatcher.js +1 -1
  38. package/lib/server/dispatchers/dispatcher.js +1 -1
  39. package/lib/server/dispatchers/frameDispatcher.js +8 -1
  40. package/lib/server/dispatchers/tracingDispatcher.js +10 -0
  41. package/lib/server/dom.js +79 -36
  42. package/lib/server/fetch.js +30 -17
  43. package/lib/server/firefox/ffExecutionContext.js +0 -12
  44. package/lib/server/firefox/ffNetworkManager.js +1 -1
  45. package/lib/server/frames.js +55 -62
  46. package/lib/server/index.js +0 -6
  47. package/lib/server/javascript.js +0 -6
  48. package/lib/server/page.js +32 -5
  49. package/lib/server/progress.js +0 -3
  50. package/lib/server/recorder/recorderApp.js +6 -15
  51. package/lib/server/recorder/recorderInTraceViewer.js +3 -3
  52. package/lib/server/recorder/recorderUtils.js +2 -1
  53. package/lib/server/recorder.js +66 -31
  54. package/lib/server/registry/index.js +70 -23
  55. package/lib/server/registry/nativeDeps.js +6 -3
  56. package/lib/server/socksClientCertificatesInterceptor.js +1 -1
  57. package/lib/server/trace/recorder/snapshotter.js +1 -12
  58. package/lib/server/trace/recorder/snapshotterInjected.js +19 -1
  59. package/lib/server/trace/recorder/tracing.js +69 -15
  60. package/lib/server/trace/test/inMemorySnapshotter.js +3 -3
  61. package/lib/server/trace/viewer/traceViewer.js +2 -1
  62. package/lib/server/webkit/wkBrowser.js +2 -2
  63. package/lib/server/webkit/wkExecutionContext.js +0 -13
  64. package/lib/server/webkit/wkPage.js +4 -0
  65. package/lib/utils/comparators.js +12 -30
  66. package/lib/utils/crypto.js +1 -4
  67. package/lib/utils/hostPlatform.js +6 -0
  68. package/lib/utils/isomorphic/ariaSnapshot.js +267 -0
  69. package/lib/utils/isomorphic/locatorGenerators.js +23 -5
  70. package/lib/utils/isomorphic/recorderUtils.js +36 -4
  71. package/lib/utils/isomorphic/stringUtils.js +30 -0
  72. package/lib/utils/isomorphic/urlMatch.js +5 -1
  73. package/lib/utils/network.js +1 -1
  74. package/lib/utils/sequence.js +64 -0
  75. package/lib/utils/stackTrace.js +16 -3
  76. package/lib/utils/zones.js +32 -23
  77. package/lib/utilsBundle.js +4 -5
  78. package/lib/utilsBundleImpl/index.js +190 -33
  79. package/lib/vite/htmlReport/index.html +19 -16
  80. package/lib/vite/recorder/assets/codeMirrorModule-AFvV6hAs.js +24 -0
  81. package/lib/vite/recorder/assets/index-_cTWgVuJ.js +184 -0
  82. package/lib/vite/recorder/assets/{index-BW-aOBcL.css → index-iA1aAGZg.css} +1 -1
  83. package/lib/vite/recorder/index.html +2 -2
  84. package/lib/vite/traceViewer/assets/codeMirrorModule-BWCrdKft.js +24 -0
  85. package/lib/vite/traceViewer/assets/inspectorTab-C_9qyxv5.js +68 -0
  86. package/lib/vite/traceViewer/assets/workbench-DsQEOQud.js +9 -0
  87. package/lib/vite/traceViewer/{embedded.BlHoW5LY.js → embedded.D4x_-tXl.js} +1 -1
  88. package/lib/vite/traceViewer/embedded.html +5 -5
  89. package/lib/vite/traceViewer/{index.DaWVfou1.js → index.BskMikzx.js} +1 -1
  90. package/lib/vite/traceViewer/index.html +24 -7
  91. package/lib/vite/traceViewer/{inspectorTab.DLjBDrQR.css → inspectorTab.DEOUW62d.css} +1 -1
  92. package/lib/vite/traceViewer/recorder.Dsk1wX5k.js +2 -0
  93. package/lib/vite/traceViewer/recorder.html +3 -3
  94. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  95. package/lib/vite/traceViewer/uiMode.CzKr-TMc.js +5 -0
  96. package/lib/vite/traceViewer/uiMode.html +6 -6
  97. package/lib/vite/traceViewer/{uiMode.CAYqod-m.css → uiMode.voC1ZiOQ.css} +1 -1
  98. package/lib/vite/traceViewer/workbench.C-zR9ysA.css +1 -0
  99. package/package.json +1 -1
  100. package/types/protocol.d.ts +58 -10
  101. package/types/types.d.ts +116 -20
  102. package/lib/third_party/diff_match_patch.js +0 -2222
  103. package/lib/vite/recorder/assets/codeMirrorModule-baozm8ur.js +0 -24
  104. package/lib/vite/recorder/assets/index-2ElAIWFB.js +0 -42
  105. package/lib/vite/traceViewer/assets/codeMirrorModule-Bh1rfd2w.js +0 -24
  106. package/lib/vite/traceViewer/assets/inspectorTab-7GHnKvSD.js +0 -64
  107. package/lib/vite/traceViewer/assets/workbench-DPQnTHYP.js +0 -9
  108. package/lib/vite/traceViewer/recorder.C4zxcvd2.js +0 -2
  109. package/lib/vite/traceViewer/uiMode.mTXWniJb.js +0 -5
  110. package/lib/vite/traceViewer/workbench.D3JVcA9K.css +0 -1
@@ -96,8 +96,10 @@ class AndroidDeviceDispatcher extends _dispatcher.Dispatcher {
96
96
  await this._object.send('swipe', params);
97
97
  }
98
98
  async info(params) {
99
+ const info = await this._object.send('info', params);
100
+ fixupAndroidElementInfo(info);
99
101
  return {
100
- info: await this._object.send('info', params)
102
+ info
101
103
  };
102
104
  }
103
105
  async inputType(params) {
@@ -190,4 +192,13 @@ class AndroidSocketDispatcher extends _dispatcher.Dispatcher {
190
192
  }
191
193
  }
192
194
  exports.AndroidSocketDispatcher = AndroidSocketDispatcher;
193
- const keyMap = new Map([['Unknown', 0], ['SoftLeft', 1], ['SoftRight', 2], ['Home', 3], ['Back', 4], ['Call', 5], ['EndCall', 6], ['0', 7], ['1', 8], ['2', 9], ['3', 10], ['4', 11], ['5', 12], ['6', 13], ['7', 14], ['8', 15], ['9', 16], ['Star', 17], ['*', 17], ['Pound', 18], ['#', 18], ['DialUp', 19], ['DialDown', 20], ['DialLeft', 21], ['DialRight', 22], ['DialCenter', 23], ['VolumeUp', 24], ['VolumeDown', 25], ['Power', 26], ['Camera', 27], ['Clear', 28], ['A', 29], ['B', 30], ['C', 31], ['D', 32], ['E', 33], ['F', 34], ['G', 35], ['H', 36], ['I', 37], ['J', 38], ['K', 39], ['L', 40], ['M', 41], ['N', 42], ['O', 43], ['P', 44], ['Q', 45], ['R', 46], ['S', 47], ['T', 48], ['U', 49], ['V', 50], ['W', 51], ['X', 52], ['Y', 53], ['Z', 54], ['Comma', 55], [',', 55], ['Period', 56], ['.', 56], ['AltLeft', 57], ['AltRight', 58], ['ShiftLeft', 59], ['ShiftRight', 60], ['Tab', 61], ['\t', 61], ['Space', 62], [' ', 62], ['Sym', 63], ['Explorer', 64], ['Envelop', 65], ['Enter', 66], ['Del', 67], ['Grave', 68], ['Minus', 69], ['-', 69], ['Equals', 70], ['=', 70], ['LeftBracket', 71], ['(', 71], ['RightBracket', 72], [')', 72], ['Backslash', 73], ['\\', 73], ['Semicolon', 74], [';', 74], ['Apostrophe', 75], ['`', 75], ['Slash', 76], ['/', 76], ['At', 77], ['@', 77], ['Num', 78], ['HeadsetHook', 79], ['Focus', 80], ['Plus', 81], ['Menu', 82], ['Notification', 83], ['Search', 84], ['ChannelUp', 166], ['ChannelDown', 167], ['AppSwitch', 187], ['Assist', 219], ['Cut', 277], ['Copy', 278], ['Paste', 279]]);
195
+ const keyMap = new Map([['Unknown', 0], ['SoftLeft', 1], ['SoftRight', 2], ['Home', 3], ['Back', 4], ['Call', 5], ['EndCall', 6], ['0', 7], ['1', 8], ['2', 9], ['3', 10], ['4', 11], ['5', 12], ['6', 13], ['7', 14], ['8', 15], ['9', 16], ['Star', 17], ['*', 17], ['Pound', 18], ['#', 18], ['DialUp', 19], ['DialDown', 20], ['DialLeft', 21], ['DialRight', 22], ['DialCenter', 23], ['VolumeUp', 24], ['VolumeDown', 25], ['Power', 26], ['Camera', 27], ['Clear', 28], ['A', 29], ['B', 30], ['C', 31], ['D', 32], ['E', 33], ['F', 34], ['G', 35], ['H', 36], ['I', 37], ['J', 38], ['K', 39], ['L', 40], ['M', 41], ['N', 42], ['O', 43], ['P', 44], ['Q', 45], ['R', 46], ['S', 47], ['T', 48], ['U', 49], ['V', 50], ['W', 51], ['X', 52], ['Y', 53], ['Z', 54], ['Comma', 55], [',', 55], ['Period', 56], ['.', 56], ['AltLeft', 57], ['AltRight', 58], ['ShiftLeft', 59], ['ShiftRight', 60], ['Tab', 61], ['\t', 61], ['Space', 62], [' ', 62], ['Sym', 63], ['Explorer', 64], ['Envelop', 65], ['Enter', 66], ['Del', 67], ['Grave', 68], ['Minus', 69], ['-', 69], ['Equals', 70], ['=', 70], ['LeftBracket', 71], ['(', 71], ['RightBracket', 72], [')', 72], ['Backslash', 73], ['\\', 73], ['Semicolon', 74], [';', 74], ['Apostrophe', 75], ['`', 75], ['Slash', 76], ['/', 76], ['At', 77], ['@', 77], ['Num', 78], ['HeadsetHook', 79], ['Focus', 80], ['Plus', 81], ['Menu', 82], ['Notification', 83], ['Search', 84], ['ChannelUp', 166], ['ChannelDown', 167], ['AppSwitch', 187], ['Assist', 219], ['Cut', 277], ['Copy', 278], ['Paste', 279]]);
196
+ function fixupAndroidElementInfo(info) {
197
+ // Some of the properties are nullable, see https://developer.android.com/reference/androidx/test/uiautomator/UiObject2.
198
+ info.clazz = info.clazz || '';
199
+ info.pkg = info.pkg || '';
200
+ info.res = info.res || '';
201
+ info.desc = info.desc || '';
202
+ info.text = info.text || '';
203
+ for (const child of info.children || []) fixupAndroidElementInfo(child);
204
+ }
@@ -81,7 +81,7 @@ class DebugControllerDispatcher extends _dispatcher.Dispatcher {
81
81
  await this._object.setRecorderMode(params);
82
82
  }
83
83
  async highlight(params) {
84
- await this._object.highlight(params.selector);
84
+ await this._object.highlight(params);
85
85
  }
86
86
  async hideHighlight() {
87
87
  await this._object.hideHighlight();
@@ -384,7 +384,7 @@ class DispatcherConnection {
384
384
  callMetadata.endTime = (0, _utils.monotonicTime)();
385
385
  await (sdkObject === null || sdkObject === void 0 ? void 0 : sdkObject.instrumentation.onAfterCall(sdkObject, callMetadata));
386
386
  }
387
- if (response.error) response.log = callMetadata.log;
387
+ if (response.error) response.log = (0, _utils.compressCallLog)(callMetadata.log);
388
388
  this.onmessage(response);
389
389
  }
390
390
  }
@@ -10,6 +10,7 @@ var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
10
10
  var _jsHandleDispatcher = require("./jsHandleDispatcher");
11
11
  var _networkDispatchers = require("./networkDispatchers");
12
12
  var _utils = require("../../utils");
13
+ var _ariaSnapshot = require("../ariaSnapshot");
13
14
  /**
14
15
  * Copyright (c) Microsoft Corporation.
15
16
  *
@@ -274,7 +275,8 @@ class FrameDispatcher extends _dispatcher.Dispatcher {
274
275
  }
275
276
  async expect(params, metadata) {
276
277
  metadata.potentiallyClosesScope = true;
277
- const expectedValue = params.expectedValue ? (0, _jsHandleDispatcher.parseArgument)(params.expectedValue) : undefined;
278
+ let expectedValue = params.expectedValue ? (0, _jsHandleDispatcher.parseArgument)(params.expectedValue) : undefined;
279
+ if (params.expression === 'to.match.aria' && expectedValue) expectedValue = (0, _ariaSnapshot.parseAriaSnapshot)(expectedValue);
278
280
  const result = await this._frame.expect(metadata, params.selector, {
279
281
  ...params,
280
282
  expectedValue
@@ -282,5 +284,10 @@ class FrameDispatcher extends _dispatcher.Dispatcher {
282
284
  if (result.received !== undefined) result.received = (0, _jsHandleDispatcher.serializeResult)(result.received);
283
285
  return result;
284
286
  }
287
+ async ariaSnapshot(params, metadata) {
288
+ return {
289
+ snapshot: await this._frame.ariaSnapshot(metadata, params.selector, params)
290
+ };
291
+ }
285
292
  }
286
293
  exports.FrameDispatcher = FrameDispatcher;
@@ -37,6 +37,16 @@ class TracingDispatcher extends _dispatcher.Dispatcher {
37
37
  async tracingStartChunk(params) {
38
38
  return await this._object.startChunk(params);
39
39
  }
40
+ async tracingGroup(params, metadata) {
41
+ const {
42
+ name,
43
+ location
44
+ } = params;
45
+ await this._object.group(name, location, metadata);
46
+ }
47
+ async tracingGroupEnd(params) {
48
+ await this._object.groupEnd();
49
+ }
40
50
  async tracingStopChunk(params) {
41
51
  const {
42
52
  artifact,
package/lib/server/dom.js CHANGED
@@ -225,17 +225,21 @@ class ElementHandle extends js.JSHandle {
225
225
  // Allow 1x1 elements. Compensate for rounding errors by comparing with 0.99 instead.
226
226
  const filtered = quads.map(quad => intersectQuadWithViewport(quad)).filter(quad => computeQuadArea(quad) > 0.99);
227
227
  if (!filtered.length) return 'error:notinviewport';
228
- // Return the middle point of the first quad.
229
- const result = {
230
- x: 0,
231
- y: 0
232
- };
233
- for (const point of filtered[0]) {
234
- result.x += point.x / 4;
235
- result.y += point.y / 4;
228
+ if (this._page._browserContext._browser.options.name === 'firefox') {
229
+ // Firefox internally uses integer coordinates, so 8.x is converted to 8 or 9 when clicking.
230
+ //
231
+ // This does not work nicely for small elements. For example, 1x1 square with corners
232
+ // (8;8) and (9;9) is targeted when clicking at (8;8) but not when clicking at (9;9).
233
+ // So, clicking at (8.x;8.y) will sometimes click at (9;9) and miss the target.
234
+ //
235
+ // Therefore, we try to find an integer point within a quad to make sure we click inside the element.
236
+ for (const quad of filtered) {
237
+ const integerPoint = findIntegerPointInsideQuad(quad);
238
+ if (integerPoint) return integerPoint;
239
+ }
236
240
  }
237
- compensateHalfIntegerRoundingError(result);
238
- return result;
241
+ // Return the middle point of the first quad.
242
+ return quadMiddlePoint(filtered[0]);
239
243
  }
240
244
  async _offsetPoint(offset) {
241
245
  const [box, border] = await Promise.all([this.boundingBox(), this.evaluateInUtility(([injected, node]) => injected.getElementBorderWidth(node), {}).catch(e => {})]);
@@ -253,7 +257,7 @@ class ElementHandle extends js.JSHandle {
253
257
  const waitTime = [0, 20, 100, 100, 500];
254
258
  while (progress.isRunning()) {
255
259
  if (retry) {
256
- progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}, attempt #${retry}`);
260
+ progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}`);
257
261
  const timeout = waitTime[Math.min(retry - 1, waitTime.length - 1)];
258
262
  if (timeout) {
259
263
  progress.log(` waiting ${timeout}ms`);
@@ -263,7 +267,7 @@ class ElementHandle extends js.JSHandle {
263
267
  } else {
264
268
  progress.log(`attempting ${actionName} action${options.trial ? ' (trial run)' : ''}`);
265
269
  }
266
- if (!options.skipLocatorHandlersCheckpoint && !options.force) await this._frame._page.performLocatorHandlersCheckpoint(progress);
270
+ if (!options.skipActionPreChecks && !options.force) await this._frame._page.performActionPreChecks(progress);
267
271
  const result = await action(retry);
268
272
  ++retry;
269
273
  if (result === 'error:notvisible') {
@@ -294,7 +298,7 @@ class ElementHandle extends js.JSHandle {
294
298
  }
295
299
  async _retryPointerAction(progress, actionName, waitForEnabled, action, options) {
296
300
  // Note: do not perform locator handlers checkpoint to avoid moving the mouse in the middle of a drag operation.
297
- const skipLocatorHandlersCheckpoint = actionName === 'move and up';
301
+ const skipActionPreChecks = actionName === 'move and up';
298
302
  return await this._retryAction(progress, actionName, async retry => {
299
303
  // By default, we scroll with protocol method to reveal the action point.
300
304
  // However, that might not work to scroll from under position:sticky elements
@@ -314,7 +318,7 @@ class ElementHandle extends js.JSHandle {
314
318
  return await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);
315
319
  }, {
316
320
  ...options,
317
- skipLocatorHandlersCheckpoint
321
+ skipActionPreChecks
318
322
  });
319
323
  }
320
324
  async _performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options) {
@@ -367,7 +371,7 @@ class ElementHandle extends js.JSHandle {
367
371
  if (typeof maybePoint === 'string') return maybePoint;
368
372
  const point = roundPoint(maybePoint);
369
373
  progress.metadata.point = point;
370
- await progress.beforeInputAction(this);
374
+ await this.instrumentation.onBeforeInputAction(this, progress.metadata);
371
375
  let hitTargetInterceptionHandle;
372
376
  if (force) {
373
377
  progress.log(` forcing action`);
@@ -433,9 +437,16 @@ class ElementHandle extends js.JSHandle {
433
437
  progress.log(' navigations have finished');
434
438
  return 'done';
435
439
  }
440
+ async _markAsTargetElement(metadata) {
441
+ if (!metadata.id) return;
442
+ await this.evaluateInUtility(([injected, node, callId]) => {
443
+ if (node.nodeType === 1 /* Node.ELEMENT_NODE */) injected.markTargetElements(new Set([node]), callId);
444
+ }, metadata.id);
445
+ }
436
446
  async hover(metadata, options) {
437
447
  const controller = new _progress.ProgressController(metadata, this);
438
448
  return controller.run(async progress => {
449
+ await this._markAsTargetElement(metadata);
439
450
  const result = await this._hover(progress, options);
440
451
  return assertDone(throwRetargetableDOMError(result));
441
452
  }, this._page._timeoutSettings.timeout(options));
@@ -449,6 +460,7 @@ class ElementHandle extends js.JSHandle {
449
460
  async click(metadata, options = {}) {
450
461
  const controller = new _progress.ProgressController(metadata, this);
451
462
  return controller.run(async progress => {
463
+ await this._markAsTargetElement(metadata);
452
464
  const result = await this._click(progress, {
453
465
  ...options,
454
466
  waitAfter: !options.noWaitAfter
@@ -462,6 +474,7 @@ class ElementHandle extends js.JSHandle {
462
474
  async dblclick(metadata, options) {
463
475
  const controller = new _progress.ProgressController(metadata, this);
464
476
  return controller.run(async progress => {
477
+ await this._markAsTargetElement(metadata);
465
478
  const result = await this._dblclick(progress, options);
466
479
  return assertDone(throwRetargetableDOMError(result));
467
480
  }, this._page._timeoutSettings.timeout(options));
@@ -475,6 +488,7 @@ class ElementHandle extends js.JSHandle {
475
488
  async tap(metadata, options = {}) {
476
489
  const controller = new _progress.ProgressController(metadata, this);
477
490
  return controller.run(async progress => {
491
+ await this._markAsTargetElement(metadata);
478
492
  const result = await this._tap(progress, options);
479
493
  return assertDone(throwRetargetableDOMError(result));
480
494
  }, this._page._timeoutSettings.timeout(options));
@@ -488,6 +502,7 @@ class ElementHandle extends js.JSHandle {
488
502
  async selectOption(metadata, elements, values, options) {
489
503
  const controller = new _progress.ProgressController(metadata, this);
490
504
  return controller.run(async progress => {
505
+ await this._markAsTargetElement(metadata);
491
506
  const result = await this._selectOption(progress, elements, values, options);
492
507
  return throwRetargetableDOMError(result);
493
508
  }, this._page._timeoutSettings.timeout(options));
@@ -495,7 +510,7 @@ class ElementHandle extends js.JSHandle {
495
510
  async _selectOption(progress, elements, values, options) {
496
511
  let resultingOptions = [];
497
512
  await this._retryAction(progress, 'select option', async () => {
498
- await progress.beforeInputAction(this);
513
+ await this.instrumentation.onBeforeInputAction(this, progress.metadata);
499
514
  if (!options.force) progress.log(` waiting for element to be visible and enabled`);
500
515
  const optionsToSelect = [...elements, ...values];
501
516
  const result = await this.evaluateInUtility(async ([injected, node, {
@@ -523,6 +538,7 @@ class ElementHandle extends js.JSHandle {
523
538
  async fill(metadata, value, options = {}) {
524
539
  const controller = new _progress.ProgressController(metadata, this);
525
540
  return controller.run(async progress => {
541
+ await this._markAsTargetElement(metadata);
526
542
  const result = await this._fill(progress, value, options);
527
543
  assertDone(throwRetargetableDOMError(result));
528
544
  }, this._page._timeoutSettings.timeout(options));
@@ -530,7 +546,7 @@ class ElementHandle extends js.JSHandle {
530
546
  async _fill(progress, value, options) {
531
547
  progress.log(` fill("${value}")`);
532
548
  return await this._retryAction(progress, 'fill', async () => {
533
- await progress.beforeInputAction(this);
549
+ await this.instrumentation.onBeforeInputAction(this, progress.metadata);
534
550
  if (!options.force) progress.log(' waiting for element to be visible, enabled and editable');
535
551
  const result = await this.evaluateInUtility(async ([injected, node, {
536
552
  value,
@@ -578,6 +594,7 @@ class ElementHandle extends js.JSHandle {
578
594
  const inputFileItems = await (0, _fileUploadUtils.prepareFilesForUpload)(this._frame, params);
579
595
  const controller = new _progress.ProgressController(metadata, this);
580
596
  return controller.run(async progress => {
597
+ await this._markAsTargetElement(metadata);
581
598
  const result = await this._setInputFiles(progress, inputFileItems);
582
599
  return assertDone(throwRetargetableDOMError(result));
583
600
  }, this._page._timeoutSettings.timeout(params));
@@ -607,7 +624,7 @@ class ElementHandle extends js.JSHandle {
607
624
  });
608
625
  if (result === 'error:notconnected' || !result.asElement()) return 'error:notconnected';
609
626
  const retargeted = result.asElement();
610
- await progress.beforeInputAction(this);
627
+ await this.instrumentation.onBeforeInputAction(this, progress.metadata);
611
628
  progress.throwIfAborted(); // Avoid action that has side-effects.
612
629
  if (localPaths || localDirectory) {
613
630
  const localPathsOrDirectory = localDirectory ? [localDirectory] : localPaths;
@@ -628,6 +645,7 @@ class ElementHandle extends js.JSHandle {
628
645
  async focus(metadata) {
629
646
  const controller = new _progress.ProgressController(metadata, this);
630
647
  await controller.run(async progress => {
648
+ await this._markAsTargetElement(metadata);
631
649
  const result = await this._focus(progress);
632
650
  return assertDone(throwRetargetableDOMError(result));
633
651
  }, 0);
@@ -643,13 +661,14 @@ class ElementHandle extends js.JSHandle {
643
661
  async type(metadata, text, options) {
644
662
  const controller = new _progress.ProgressController(metadata, this);
645
663
  return controller.run(async progress => {
664
+ await this._markAsTargetElement(metadata);
646
665
  const result = await this._type(progress, text, options);
647
666
  return assertDone(throwRetargetableDOMError(result));
648
667
  }, this._page._timeoutSettings.timeout(options));
649
668
  }
650
669
  async _type(progress, text, options) {
651
670
  progress.log(`elementHandle.type("${text}")`);
652
- await progress.beforeInputAction(this);
671
+ await this.instrumentation.onBeforeInputAction(this, progress.metadata);
653
672
  const result = await this._focus(progress, true /* resetSelectionIfNotFocused */);
654
673
  if (result !== 'done') return result;
655
674
  progress.throwIfAborted(); // Avoid action that has side-effects.
@@ -659,13 +678,14 @@ class ElementHandle extends js.JSHandle {
659
678
  async press(metadata, key, options) {
660
679
  const controller = new _progress.ProgressController(metadata, this);
661
680
  return controller.run(async progress => {
681
+ await this._markAsTargetElement(metadata);
662
682
  const result = await this._press(progress, key, options);
663
683
  return assertDone(throwRetargetableDOMError(result));
664
684
  }, this._page._timeoutSettings.timeout(options));
665
685
  }
666
686
  async _press(progress, key, options) {
667
687
  progress.log(`elementHandle.press("${key}")`);
668
- await progress.beforeInputAction(this);
688
+ await this.instrumentation.onBeforeInputAction(this, progress.metadata);
669
689
  return this._page._frameManager.waitForSignalsCreatedBy(progress, !options.noWaitAfter, async () => {
670
690
  const result = await this._focus(progress, true /* resetSelectionIfNotFocused */);
671
691
  if (result !== 'done') return result;
@@ -693,6 +713,7 @@ class ElementHandle extends js.JSHandle {
693
713
  const result = await this.evaluateInUtility(([injected, node]) => injected.elementState(node, 'checked'), {});
694
714
  return throwRetargetableDOMError(result);
695
715
  };
716
+ await this._markAsTargetElement(progress.metadata);
696
717
  if ((await isChecked()) === state) return 'done';
697
718
  const result = await this._click(progress, {
698
719
  ...options,
@@ -706,6 +727,9 @@ class ElementHandle extends js.JSHandle {
706
727
  async boundingBox() {
707
728
  return this._page._delegate.getBoundingBox(this);
708
729
  }
730
+ async ariaSnapshot() {
731
+ return await this.evaluateInUtility(([injected, element]) => injected.ariaSnapshot(element), {});
732
+ }
709
733
  async screenshot(metadata, options = {}) {
710
734
  const controller = new _progress.ProgressController(metadata, this);
711
735
  return controller.run(progress => this._page._screenshotter.screenshotElement(progress, this, options), this._page._timeoutSettings.timeout(options));
@@ -825,21 +849,40 @@ function roundPoint(point) {
825
849
  y: (point.y * 100 | 0) / 100
826
850
  };
827
851
  }
828
- function compensateHalfIntegerRoundingError(point) {
829
- // Firefox internally uses integer coordinates, so 8.5 is converted to 9 when clicking.
830
- //
831
- // This does not work nicely for small elements. For example, 1x1 square with corners
832
- // (8;8) and (9;9) is targeted when clicking at (8;8) but not when clicking at (9;9).
833
- // So, clicking at (8.5;8.5) will effectively click at (9;9) and miss the target.
834
- //
835
- // Therefore, we skew half-integer values from the interval (8.49, 8.51) towards
836
- // (8.47, 8.49) that is rounded towards 8. This means clicking at (8.5;8.5) will
837
- // be replaced with (8.48;8.48) and will effectively click at (8;8).
838
- //
839
- // Other browsers use float coordinates, so this change should not matter.
840
- const remainderX = point.x - Math.floor(point.x);
841
- if (remainderX > 0.49 && remainderX < 0.51) point.x -= 0.02;
842
- const remainderY = point.y - Math.floor(point.y);
843
- if (remainderY > 0.49 && remainderY < 0.51) point.y -= 0.02;
852
+ function quadMiddlePoint(quad) {
853
+ const result = {
854
+ x: 0,
855
+ y: 0
856
+ };
857
+ for (const point of quad) {
858
+ result.x += point.x / 4;
859
+ result.y += point.y / 4;
860
+ }
861
+ return result;
862
+ }
863
+ function triangleArea(p1, p2, p3) {
864
+ return Math.abs(p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) / 2;
865
+ }
866
+ function isPointInsideQuad(point, quad) {
867
+ const area1 = triangleArea(point, quad[0], quad[1]) + triangleArea(point, quad[1], quad[2]) + triangleArea(point, quad[2], quad[3]) + triangleArea(point, quad[3], quad[0]);
868
+ const area2 = triangleArea(quad[0], quad[1], quad[2]) + triangleArea(quad[1], quad[2], quad[3]);
869
+ // Check that point is inside the quad.
870
+ if (Math.abs(area1 - area2) > 0.1) return false;
871
+ // Check that point is not on the right/bottom edge, because clicking
872
+ // there does not actually click the element.
873
+ return point.x < Math.max(quad[0].x, quad[1].x, quad[2].x, quad[3].x) && point.y < Math.max(quad[0].y, quad[1].y, quad[2].y, quad[3].y);
874
+ }
875
+ function findIntegerPointInsideQuad(quad) {
876
+ // Try all four rounding directions of the middle point.
877
+ const point = quadMiddlePoint(quad);
878
+ point.x = Math.floor(point.x);
879
+ point.y = Math.floor(point.y);
880
+ if (isPointInsideQuad(point, quad)) return point;
881
+ point.x += 1;
882
+ if (isPointInsideQuad(point, quad)) return point;
883
+ point.y += 1;
884
+ if (isPointInsideQuad(point, quad)) return point;
885
+ point.x -= 1;
886
+ if (isPointInsideQuad(point, quad)) return point;
844
887
  }
845
888
  const kUnableToAdoptErrorMessage = exports.kUnableToAdoptErrorMessage = 'Unable to adopt element handle from a different document';
@@ -8,7 +8,6 @@ exports.createProxyAgent = createProxyAgent;
8
8
  var _http = _interopRequireDefault(require("http"));
9
9
  var _https = _interopRequireDefault(require("https"));
10
10
  var _stream = require("stream");
11
- var _url = _interopRequireDefault(require("url"));
12
11
  var _zlib = _interopRequireDefault(require("zlib"));
13
12
  var _timeoutSettings = require("../common/timeoutSettings");
14
13
  var _userAgent = require("../utils/userAgent");
@@ -91,7 +90,7 @@ class APIRequestContext extends _instrumentation.SdkObject {
91
90
  value
92
91
  } of params.headers) setHeader(headers, name, value);
93
92
  }
94
- const requestUrl = new URL(params.url, defaults.baseURL);
93
+ const requestUrl = new URL((0, _utils.constructURLBasedOnBaseURL)(defaults.baseURL, params.url));
95
94
  if (params.encodedParams) {
96
95
  requestUrl.search = params.encodedParams;
97
96
  } else if (params.params) {
@@ -218,6 +217,7 @@ class APIRequestContext extends _instrumentation.SdkObject {
218
217
  agent
219
218
  };
220
219
  const startAt = (0, _utils.monotonicTime)();
220
+ let reusedSocketAt;
221
221
  let dnsLookupAt;
222
222
  let tcpConnectionAt;
223
223
  let tlsHandshakeAt;
@@ -232,15 +232,16 @@ class APIRequestContext extends _instrumentation.SdkObject {
232
232
  var _tlsHandshakeAt;
233
233
  const endAt = (0, _utils.monotonicTime)();
234
234
  // spec: http://www.softwareishard.com/blog/har-12-spec/#timings
235
+ const connectEnd = (_tlsHandshakeAt = tlsHandshakeAt) !== null && _tlsHandshakeAt !== void 0 ? _tlsHandshakeAt : tcpConnectionAt;
235
236
  const timings = {
236
237
  send: requestFinishAt - startAt,
237
238
  wait: responseAt - requestFinishAt,
238
239
  receive: endAt - responseAt,
239
240
  dns: dnsLookupAt ? dnsLookupAt - startAt : -1,
240
- connect: ((_tlsHandshakeAt = tlsHandshakeAt) !== null && _tlsHandshakeAt !== void 0 ? _tlsHandshakeAt : tcpConnectionAt) - startAt,
241
+ connect: connectEnd ? connectEnd - startAt : -1,
241
242
  // "If [ssl] is defined then the time is also included in the connect field "
242
243
  ssl: tlsHandshakeAt ? tlsHandshakeAt - tcpConnectionAt : -1,
243
- blocked: -1
244
+ blocked: reusedSocketAt ? reusedSocketAt - startAt : -1
244
245
  };
245
246
  const requestFinishedEvent = {
246
247
  requestEvent,
@@ -387,16 +388,23 @@ class APIRequestContext extends _instrumentation.SdkObject {
387
388
  }));
388
389
  request.on('close', () => _utils.eventsHelper.removeEventListeners(listeners));
389
390
  request.on('socket', socket => {
391
+ var _tcpConnectionAt, _tcpConnectionAt3;
392
+ if (request.reusedSocket) {
393
+ reusedSocketAt = (0, _utils.monotonicTime)();
394
+ return;
395
+ }
396
+
390
397
  // happy eyeballs don't emit lookup and connect events, so we use our custom ones
391
398
  const happyEyeBallsTimings = (0, _happyEyeballs.timingForSocket)(socket);
392
399
  dnsLookupAt = happyEyeBallsTimings.dnsLookupAt;
393
- tcpConnectionAt = happyEyeBallsTimings.tcpConnectionAt;
400
+ (_tcpConnectionAt = tcpConnectionAt) !== null && _tcpConnectionAt !== void 0 ? _tcpConnectionAt : tcpConnectionAt = happyEyeBallsTimings.tcpConnectionAt;
394
401
 
395
402
  // non-happy-eyeballs sockets
396
403
  listeners.push(_utils.eventsHelper.addEventListener(socket, 'lookup', () => {
397
404
  dnsLookupAt = (0, _utils.monotonicTime)();
398
405
  }), _utils.eventsHelper.addEventListener(socket, 'connect', () => {
399
- tcpConnectionAt = (0, _utils.monotonicTime)();
406
+ var _tcpConnectionAt2;
407
+ (_tcpConnectionAt2 = tcpConnectionAt) !== null && _tcpConnectionAt2 !== void 0 ? _tcpConnectionAt2 : tcpConnectionAt = (0, _utils.monotonicTime)();
400
408
  }), _utils.eventsHelper.addEventListener(socket, 'secureConnect', () => {
401
409
  tlsHandshakeAt = (0, _utils.monotonicTime)();
402
410
  if (socket instanceof _tls.TLSSocket) {
@@ -411,12 +419,21 @@ class APIRequestContext extends _instrumentation.SdkObject {
411
419
  };
412
420
  }
413
421
  }));
422
+
423
+ // when using socks proxy, having the socket means the connection got established
424
+ if (agent instanceof _utilsBundle.SocksProxyAgent) (_tcpConnectionAt3 = tcpConnectionAt) !== null && _tcpConnectionAt3 !== void 0 ? _tcpConnectionAt3 : tcpConnectionAt = (0, _utils.monotonicTime)();
414
425
  serverIPAddress = socket.remoteAddress;
415
426
  serverPort = socket.remotePort;
416
427
  });
417
428
  request.on('finish', () => {
418
429
  requestFinishAt = (0, _utils.monotonicTime)();
419
430
  });
431
+
432
+ // http proxy
433
+ request.on('proxyConnect', () => {
434
+ var _tcpConnectionAt4;
435
+ (_tcpConnectionAt4 = tcpConnectionAt) !== null && _tcpConnectionAt4 !== void 0 ? _tcpConnectionAt4 : tcpConnectionAt = (0, _utils.monotonicTime)();
436
+ });
420
437
  progress.log(`→ ${options.method} ${url.toString()}`);
421
438
  if (options.headers) {
422
439
  for (const [name, value] of Object.entries(options.headers)) progress.log(` ${name}: ${value}`);
@@ -562,17 +579,13 @@ class GlobalAPIRequestContext extends APIRequestContext {
562
579
  }
563
580
  exports.GlobalAPIRequestContext = GlobalAPIRequestContext;
564
581
  function createProxyAgent(proxy) {
565
- var _proxyOpts$protocol;
566
- const proxyOpts = _url.default.parse(proxy.server);
567
- if ((_proxyOpts$protocol = proxyOpts.protocol) !== null && _proxyOpts$protocol !== void 0 && _proxyOpts$protocol.startsWith('socks')) {
568
- return new _utilsBundle.SocksProxyAgent({
569
- host: proxyOpts.hostname,
570
- port: proxyOpts.port || undefined
571
- });
572
- }
573
- if (proxy.username) proxyOpts.auth = `${proxy.username}:${proxy.password || ''}`;
574
- // TODO: We should use HttpProxyAgent conditional on proxyOpts.protocol instead of always using CONNECT method.
575
- return new _utilsBundle.HttpsProxyAgent(proxyOpts);
582
+ var _proxyURL$protocol;
583
+ const proxyURL = new URL(proxy.server);
584
+ if ((_proxyURL$protocol = proxyURL.protocol) !== null && _proxyURL$protocol !== void 0 && _proxyURL$protocol.startsWith('socks')) return new _utilsBundle.SocksProxyAgent(proxyURL);
585
+ if (proxy.username) proxyURL.username = proxy.username;
586
+ if (proxy.password) proxyURL.password = proxy.password;
587
+ // TODO: We should use HttpProxyAgent conditional on proxyURL.protocol instead of always using CONNECT method.
588
+ return new _utilsBundle.HttpsProxyAgent(proxyURL);
576
589
  }
577
590
  function toHeadersArray(rawHeaders) {
578
591
  const result = [];
@@ -52,18 +52,6 @@ class FFExecutionContext {
52
52
  checkException(payload.exceptionDetails);
53
53
  return payload.result.objectId;
54
54
  }
55
- rawCallFunctionNoReply(func, ...args) {
56
- this._session.send('Runtime.callFunction', {
57
- functionDeclaration: func.toString(),
58
- args: args.map(a => a instanceof js.JSHandle ? {
59
- objectId: a._objectId
60
- } : {
61
- value: a
62
- }),
63
- returnByValue: true,
64
- executionContextId: this._executionContextId
65
- }).catch(() => {});
66
- }
67
55
  async evaluateWithArguments(expression, returnByValue, utilityScript, values, objectIds) {
68
56
  const payload = await this._session.send('Runtime.callFunction', {
69
57
  functionDeclaration: expression,
@@ -161,7 +161,7 @@ const causeToResourceType = {
161
161
  TYPE_XSLT: 'other',
162
162
  TYPE_BEACON: 'other',
163
163
  TYPE_FETCH: 'fetch',
164
- TYPE_IMAGESET: 'images',
164
+ TYPE_IMAGESET: 'image',
165
165
  TYPE_WEB_MANIFEST: 'manifest'
166
166
  };
167
167
  const internalCauseToResourceType = {