rebrowser-playwright-core 1.47.2 → 1.48.2

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 (121) hide show
  1. package/README.md +2 -0
  2. package/browsers.json +14 -10
  3. package/lib/cli/program.js +26 -14
  4. package/lib/client/api.js +6 -0
  5. package/lib/client/browserContext.js +20 -2
  6. package/lib/client/channelOwner.js +5 -1
  7. package/lib/client/connection.js +3 -0
  8. package/lib/client/fetch.js +16 -21
  9. package/lib/client/jsHandle.js +0 -8
  10. package/lib/client/localUtils.js +1 -0
  11. package/lib/client/network.js +175 -17
  12. package/lib/client/page.js +21 -0
  13. package/lib/client/playwright.js +6 -3
  14. package/lib/client/tracing.js +16 -20
  15. package/lib/generated/consoleApiSource.js +1 -1
  16. package/lib/generated/injectedScriptSource.js +1 -1
  17. package/lib/generated/pollingRecorderSource.js +7 -0
  18. package/lib/generated/webSocketMockSource.js +7 -0
  19. package/lib/protocol/validator.js +80 -14
  20. package/lib/server/bidi/bidiBrowser.js +23 -8
  21. package/lib/server/bidi/bidiChromium.js +124 -0
  22. package/lib/server/bidi/bidiConnection.js +1 -1
  23. package/lib/server/bidi/bidiExecutionContext.js +0 -3
  24. package/lib/server/bidi/bidiFirefox.js +15 -21
  25. package/lib/server/bidi/bidiInput.js +16 -32
  26. package/lib/server/bidi/bidiNetworkManager.js +39 -5
  27. package/lib/server/bidi/bidiOverCdp.js +103 -0
  28. package/lib/server/bidi/bidiPage.js +98 -25
  29. package/lib/server/bidi/bidiPdf.js +140 -0
  30. package/lib/server/bidi/third_party/firefoxPrefs.js +221 -0
  31. package/lib/server/browser.js +13 -2
  32. package/lib/server/browserContext.js +6 -23
  33. package/lib/server/browserType.js +39 -11
  34. package/lib/server/chromium/chromium.js +3 -15
  35. package/lib/server/chromium/chromiumSwitches.js +3 -1
  36. package/lib/server/chromium/crBrowser.js +4 -3
  37. package/lib/server/chromium/crExecutionContext.js +0 -7
  38. package/lib/server/chromium/crPage.js +16 -6
  39. package/lib/server/chromium/videoRecorder.js +1 -1
  40. package/lib/server/codegen/csharp.js +1 -1
  41. package/lib/server/codegen/java.js +1 -1
  42. package/lib/server/codegen/javascript.js +1 -1
  43. package/lib/server/codegen/language.js +14 -2
  44. package/lib/server/codegen/python.js +1 -1
  45. package/lib/server/cookieStore.js +73 -0
  46. package/lib/server/debugController.js +2 -2
  47. package/lib/server/deviceDescriptorsSource.json +50 -50
  48. package/lib/server/dialog.js +1 -0
  49. package/lib/server/dispatchers/browserContextDispatcher.js +19 -2
  50. package/lib/server/dispatchers/jsHandleDispatcher.js +0 -5
  51. package/lib/server/dispatchers/pageDispatcher.js +9 -0
  52. package/lib/server/dispatchers/playwrightDispatcher.js +2 -1
  53. package/lib/server/dispatchers/webSocketRouteDispatcher.js +189 -0
  54. package/lib/server/download.js +9 -2
  55. package/lib/server/fetch.js +90 -94
  56. package/lib/server/firefox/ffBrowser.js +6 -4
  57. package/lib/server/firefox/ffExecutionContext.js +0 -3
  58. package/lib/server/firefox/ffPage.js +6 -3
  59. package/lib/server/firefox/firefox.js +2 -13
  60. package/lib/server/frameSelectors.js +1 -1
  61. package/lib/server/frames.js +164 -28
  62. package/lib/server/har/harTracer.js +11 -0
  63. package/lib/server/input.js +0 -1
  64. package/lib/server/javascript.js +0 -7
  65. package/lib/server/page.js +5 -1
  66. package/lib/server/playwright.js +5 -2
  67. package/lib/server/recorder/contextRecorder.js +33 -50
  68. package/lib/server/recorder/recorderApp.js +16 -10
  69. package/lib/server/recorder/recorderCollection.js +68 -79
  70. package/lib/server/recorder/recorderInTraceViewer.js +144 -0
  71. package/lib/server/recorder/recorderRunner.js +75 -97
  72. package/lib/server/recorder/recorderUtils.js +47 -6
  73. package/lib/server/recorder.js +30 -25
  74. package/lib/server/registry/index.js +85 -4
  75. package/lib/server/socksClientCertificatesInterceptor.js +15 -3
  76. package/lib/server/trace/recorder/snapshotter.js +1 -0
  77. package/lib/server/trace/recorder/snapshotterInjected.js +2 -2
  78. package/lib/server/trace/recorder/tracing.js +58 -2
  79. package/lib/server/trace/test/inMemorySnapshotter.js +1 -1
  80. package/lib/server/trace/viewer/traceViewer.js +2 -5
  81. package/lib/server/webkit/webkit.js +1 -1
  82. package/lib/server/webkit/wkBrowser.js +6 -5
  83. package/lib/server/webkit/wkExecutionContext.js +0 -3
  84. package/lib/server/webkit/wkPage.js +7 -4
  85. package/lib/utils/happy-eyeballs.js +13 -0
  86. package/lib/utils/hostPlatform.js +2 -2
  87. package/lib/utils/httpServer.js +1 -0
  88. package/lib/utils/isomorphic/locatorGenerators.js +9 -18
  89. package/lib/utils/isomorphic/locatorParser.js +2 -2
  90. package/lib/utils/isomorphic/recorderUtils.js +195 -0
  91. package/lib/vite/htmlReport/index.html +12 -12
  92. package/lib/vite/recorder/assets/{codeMirrorModule-aW6Vz3gf.js → codeMirrorModule-baozm8ur.js} +1 -1
  93. package/lib/vite/recorder/assets/{index-DCpXOVIh.js → index-2ElAIWFB.js} +10 -15
  94. package/lib/vite/recorder/assets/{index-B-MT5gKo.css → index-BW-aOBcL.css} +1 -1
  95. package/lib/vite/recorder/index.html +2 -2
  96. package/lib/vite/traceViewer/assets/{codeMirrorModule-eFKCUIu2.js → codeMirrorModule-Bh1rfd2w.js} +1 -1
  97. package/lib/vite/traceViewer/assets/inspectorTab-7GHnKvSD.js +64 -0
  98. package/lib/vite/traceViewer/assets/workbench-DPQnTHYP.js +9 -0
  99. package/lib/vite/traceViewer/embedded.BlHoW5LY.js +2 -0
  100. package/lib/vite/traceViewer/embedded.html +5 -3
  101. package/lib/vite/traceViewer/index.DaWVfou1.js +2 -0
  102. package/lib/vite/traceViewer/index.html +5 -3
  103. package/lib/vite/traceViewer/inspectorTab.DLjBDrQR.css +1 -0
  104. package/lib/vite/traceViewer/recorder.B_SY1GJM.css +0 -0
  105. package/lib/vite/traceViewer/recorder.C4zxcvd2.js +2 -0
  106. package/lib/vite/traceViewer/recorder.html +17 -0
  107. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  108. package/lib/vite/traceViewer/{uiMode.D3cNFP6u.css → uiMode.CAYqod-m.css} +1 -1
  109. package/lib/vite/traceViewer/uiMode.html +6 -4
  110. package/lib/vite/traceViewer/uiMode.mTXWniJb.js +5 -0
  111. package/lib/vite/traceViewer/workbench.D3JVcA9K.css +1 -0
  112. package/package.json +1 -1
  113. package/types/protocol.d.ts +79 -8
  114. package/types/types.d.ts +2037 -949
  115. package/lib/generated/recorderSource.js +0 -7
  116. package/lib/vite/traceViewer/assets/workbench-D0cirtfA.js +0 -72
  117. package/lib/vite/traceViewer/embedded.BkuvsLJp.js +0 -2
  118. package/lib/vite/traceViewer/index.C968kAiC.js +0 -2
  119. package/lib/vite/traceViewer/uiMode.BkFnr4V0.js +0 -10
  120. package/lib/vite/traceViewer/workbench.DjbIuxix.css +0 -1
  121. /package/lib/server/recorder/{recorderActions.js → recorderFrontend.js} +0 -0
@@ -7,6 +7,7 @@ exports.createConnectionAsync = createConnectionAsync;
7
7
  exports.createSocket = createSocket;
8
8
  exports.createTLSSocket = createTLSSocket;
9
9
  exports.httpsHappyEyeballsAgent = exports.httpHappyEyeballsAgent = void 0;
10
+ exports.timingForSocket = timingForSocket;
10
11
  var dns = _interopRequireWildcard(require("dns"));
11
12
  var http = _interopRequireWildcard(require("http"));
12
13
  var https = _interopRequireWildcard(require("https"));
@@ -14,6 +15,7 @@ var net = _interopRequireWildcard(require("net"));
14
15
  var tls = _interopRequireWildcard(require("tls"));
15
16
  var _manualPromise = require("./manualPromise");
16
17
  var _debug = require("./debug");
18
+ var _time = require("./time");
17
19
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
18
20
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
19
21
  /**
@@ -37,6 +39,8 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
37
39
 
38
40
  // Same as in Chromium (https://source.chromium.org/chromium/chromium/src/+/5666ff4f5077a7e2f72902f3a95f5d553ea0d88d:net/socket/transport_connect_job.cc;l=102)
39
41
  const connectionAttemptDelayMs = 300;
42
+ const kDNSLookupAt = Symbol('kDNSLookupAt');
43
+ const kTCPConnectionAt = Symbol('kTCPConnectionAt');
40
44
  class HttpHappyEyeballsAgent extends http.Agent {
41
45
  createConnection(options, oncreate) {
42
46
  // There is no ambiguity in case of IP address.
@@ -101,6 +105,7 @@ async function createConnectionAsync(options, oncreate, useTLS) {
101
105
  const lookup = options.__testHookLookup || lookupAddresses;
102
106
  const hostname = clientRequestArgsToHostName(options);
103
107
  const addresses = await lookup(hostname);
108
+ const dnsLookupAt = (0, _time.monotonicTime)();
104
109
  const sockets = new Set();
105
110
  let firstError;
106
111
  let errorCount = 0;
@@ -125,10 +130,12 @@ async function createConnectionAsync(options, oncreate, useTLS) {
125
130
  port: options.port,
126
131
  host: address
127
132
  });
133
+ socket[kDNSLookupAt] = dnsLookupAt;
128
134
 
129
135
  // Each socket may fire only one of 'connect', 'timeout' or 'error' events.
130
136
  // None of these events are fired after socket.destroy() is called.
131
137
  socket.on('connect', () => {
138
+ socket[kTCPConnectionAt] = (0, _time.monotonicTime)();
132
139
  connected.resolve();
133
140
  oncreate === null || oncreate === void 0 || oncreate(null, socket);
134
141
  // TODO: Cache the result?
@@ -178,4 +185,10 @@ function clientRequestArgsToHostName(options) {
178
185
  if (options.hostname) return options.hostname;
179
186
  if (options.host) return options.host;
180
187
  throw new Error('Either options.hostname or options.host must be provided');
188
+ }
189
+ function timingForSocket(socket) {
190
+ return {
191
+ dnsLookupAt: socket[kDNSLookupAt],
192
+ tcpConnectionAt: socket[kTCPConnectionAt]
193
+ };
181
194
  }
@@ -37,9 +37,9 @@ function calculatePlatform() {
37
37
  macVersion = 'mac10.15';
38
38
  } else {
39
39
  // ver[0] >= 20
40
- const LAST_STABLE_MAC_MAJOR_VERSION = 14;
40
+ const LAST_STABLE_MACOS_MAJOR_VERSION = 15;
41
41
  // Best-effort support for MacOS beta versions.
42
- macVersion = 'mac' + Math.min(ver[0] - 9, LAST_STABLE_MAC_MAJOR_VERSION);
42
+ macVersion = 'mac' + Math.min(ver[0] - 9, LAST_STABLE_MACOS_MAJOR_VERSION);
43
43
  // BigSur is the first version that might run on Apple Silicon.
44
44
  if (_os.default.cpus().some(cpu => cpu.model.includes('Apple'))) macVersion += '-arm64';
45
45
  }
@@ -76,6 +76,7 @@ class HttpServer {
76
76
  path: '/' + this._wsGuid
77
77
  });
78
78
  wss.on('connection', ws => {
79
+ transport.onconnect();
79
80
  transport.sendEvent = (method, params) => ws.send(JSON.stringify({
80
81
  method,
81
82
  params
@@ -37,15 +37,6 @@ function asLocators(lang, selector, isFrameLocator = false, maxOutputSize = 20,
37
37
  }
38
38
  function innerAsLocators(factory, parsed, isFrameLocator = false, maxOutputSize = 20) {
39
39
  const parts = [...parsed.parts];
40
- // frameLocator('iframe').first is actually "iframe >> nth=0 >> internal:control=enter-frame"
41
- // To make it easier to parse, we turn it into "iframe >> internal:control=enter-frame >> nth=0"
42
- for (let index = 0; index < parts.length - 1; index++) {
43
- if (parts[index].name === 'nth' && parts[index + 1].name === 'internal:control' && parts[index + 1].body === 'enter-frame') {
44
- // Swap nth and enter-frame.
45
- const [nth] = parts.splice(index, 1);
46
- parts.splice(index + 1, 0, nth);
47
- }
48
- }
49
40
  const tokens = [];
50
41
  let nextBase = isFrameLocator ? 'frame-locator' : 'page';
51
42
  for (let index = 0; index < parts.length; index++) {
@@ -183,13 +174,13 @@ function innerAsLocators(factory, parsed, isFrameLocator = false, maxOutputSize
183
174
  continue;
184
175
  }
185
176
  }
186
- let locatorType = 'default';
187
- const nextPart = parts[index + 1];
188
- if (nextPart && nextPart.name === 'internal:control' && nextPart.body === 'enter-frame') {
189
- locatorType = 'frame';
177
+ if (part.name === 'internal:control' && part.body === 'enter-frame') {
178
+ tokens.push([factory.generateLocator(base, 'frame', '')]);
190
179
  nextBase = 'frame-locator';
191
- index++;
180
+ continue;
192
181
  }
182
+ let locatorType = 'default';
183
+ const nextPart = parts[index + 1];
193
184
  const selectorPart = (0, _selectorParser.stringifySelector)({
194
185
  parts: [part]
195
186
  });
@@ -277,7 +268,7 @@ class JavaScriptLocatorFactory {
277
268
  if (options.hasNotText !== undefined) return `locator(${this.quote(body)}, { hasNotText: ${this.toHasText(options.hasNotText)} })`;
278
269
  return `locator(${this.quote(body)})`;
279
270
  case 'frame':
280
- return `frameLocator(${this.quote(body)})`;
271
+ return `contentFrame()`;
281
272
  case 'nth':
282
273
  return `nth(${body})`;
283
274
  case 'first':
@@ -360,7 +351,7 @@ class PythonLocatorFactory {
360
351
  if (options.hasNotText !== undefined) return `locator(${this.quote(body)}, has_not_text=${this.toHasText(options.hasNotText)})`;
361
352
  return `locator(${this.quote(body)})`;
362
353
  case 'frame':
363
- return `frame_locator(${this.quote(body)})`;
354
+ return `content_frame`;
364
355
  case 'nth':
365
356
  return `nth(${body})`;
366
357
  case 'first':
@@ -460,7 +451,7 @@ class JavaLocatorFactory {
460
451
  if (options.hasNotText !== undefined) return `locator(${this.quote(body)}, new ${clazz}.LocatorOptions().setHasNotText(${this.toHasText(options.hasNotText)}))`;
461
452
  return `locator(${this.quote(body)})`;
462
453
  case 'frame':
463
- return `frameLocator(${this.quote(body)})`;
454
+ return `contentFrame()`;
464
455
  case 'nth':
465
456
  return `nth(${body})`;
466
457
  case 'first':
@@ -544,7 +535,7 @@ class CSharpLocatorFactory {
544
535
  if (options.hasNotText !== undefined) return `Locator(${this.quote(body)}, new() { ${this.toHasNotText(options.hasNotText)} })`;
545
536
  return `Locator(${this.quote(body)})`;
546
537
  case 'frame':
547
- return `FrameLocator(${this.quote(body)})`;
538
+ return `ContentFrame`;
548
539
  case 'nth':
549
540
  return `Nth(${body})`;
550
541
  case 'first':
@@ -63,7 +63,7 @@ function parseLocator(locator, testIdAttributeName) {
63
63
  }
64
64
 
65
65
  // Equalize languages.
66
- template = template.toLowerCase().replace(/get_by_alt_text/g, 'getbyalttext').replace(/get_by_test_id/g, 'getbytestid').replace(/get_by_([\w]+)/g, 'getby$1').replace(/has_not_text/g, 'hasnottext').replace(/has_text/g, 'hastext').replace(/has_not/g, 'hasnot').replace(/frame_locator/g, 'framelocator').replace(/[{}\s]/g, '').replace(/new\(\)/g, '').replace(/new[\w]+\.[\w]+options\(\)/g, '').replace(/\.set/g, ',set').replace(/\.or_\(/g, 'or(') // Python has "or_" instead of "or".
66
+ template = template.toLowerCase().replace(/get_by_alt_text/g, 'getbyalttext').replace(/get_by_test_id/g, 'getbytestid').replace(/get_by_([\w]+)/g, 'getby$1').replace(/has_not_text/g, 'hasnottext').replace(/has_text/g, 'hastext').replace(/has_not/g, 'hasnot').replace(/frame_locator/g, 'framelocator').replace(/content_frame/g, 'contentframe').replace(/[{}\s]/g, '').replace(/new\(\)/g, '').replace(/new[\w]+\.[\w]+options\(\)/g, '').replace(/\.set/g, ',set').replace(/\.or_\(/g, 'or(') // Python has "or_" instead of "or".
67
67
  .replace(/\.and_\(/g, 'and(') // Python has "and_" instead of "and".
68
68
  .replace(/:/g, '=').replace(/,re\.ignorecase/g, 'i').replace(/,pattern.case_insensitive/g, 'i').replace(/,regexoptions.ignorecase/g, 'i').replace(/re.compile\(([^)]+)\)/g, '$1') // Python has regex strings as r"foo"
69
69
  .replace(/pattern.compile\(([^)]+)\)/g, 'r$1').replace(/newregex\(([^)]+)\)/g, 'r$1').replace(/string=/g, '=').replace(/regex=/g, '=').replace(/,,/g, ',');
@@ -123,7 +123,7 @@ function transform(template, params, testIdAttributeName) {
123
123
  }
124
124
 
125
125
  // Transform to selector engines.
126
- template = template.replace(/\,set([\w]+)\(([^)]+)\)/g, (_, group1, group2) => ',' + group1.toLowerCase() + '=' + group2.toLowerCase()).replace(/framelocator\(([^)]+)\)/g, '$1.internal:control=enter-frame').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+),hasnottext=([^),]+)\)/g, 'locator($1).internal:has-not-text=$2').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+)\)/g, '$1').replace(/getbyrole\(([^)]+)\)/g, 'internal:role=$1').replace(/getbytext\(([^)]+)\)/g, 'internal:text=$1').replace(/getbylabel\(([^)]+)\)/g, 'internal:label=$1').replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1]`).replace(/getby(placeholder|alt|title)(?:text)?\(([^)]+)\)/g, 'internal:attr=[$1=$2]').replace(/first(\(\))?/g, 'nth=0').replace(/last(\(\))?/g, 'nth=-1').replace(/nth\(([^)]+)\)/g, 'nth=$1').replace(/filter\(,?hastext=([^)]+)\)/g, 'internal:has-text=$1').replace(/filter\(,?hasnottext=([^)]+)\)/g, 'internal:has-not-text=$1').replace(/filter\(,?has2=([^)]+)\)/g, 'internal:has=$1').replace(/filter\(,?hasnot2=([^)]+)\)/g, 'internal:has-not=$1').replace(/,exact=false/g, '').replace(/,exact=true/g, 's').replace(/\,/g, '][');
126
+ template = template.replace(/\,set([\w]+)\(([^)]+)\)/g, (_, group1, group2) => ',' + group1.toLowerCase() + '=' + group2.toLowerCase()).replace(/framelocator\(([^)]+)\)/g, '$1.internal:control=enter-frame').replace(/contentframe(\(\))?/g, 'internal:control=enter-frame').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+),hasnottext=([^),]+)\)/g, 'locator($1).internal:has-not-text=$2').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+)\)/g, '$1').replace(/getbyrole\(([^)]+)\)/g, 'internal:role=$1').replace(/getbytext\(([^)]+)\)/g, 'internal:text=$1').replace(/getbylabel\(([^)]+)\)/g, 'internal:label=$1').replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1]`).replace(/getby(placeholder|alt|title)(?:text)?\(([^)]+)\)/g, 'internal:attr=[$1=$2]').replace(/first(\(\))?/g, 'nth=0').replace(/last(\(\))?/g, 'nth=-1').replace(/nth\(([^)]+)\)/g, 'nth=$1').replace(/filter\(,?hastext=([^)]+)\)/g, 'internal:has-text=$1').replace(/filter\(,?hasnottext=([^)]+)\)/g, 'internal:has-not-text=$1').replace(/filter\(,?has2=([^)]+)\)/g, 'internal:has=$1').replace(/filter\(,?hasnot2=([^)]+)\)/g, 'internal:has-not=$1').replace(/,exact=false/g, '').replace(/,exact=true/g, 's').replace(/\,/g, '][');
127
127
  const parts = template.split('.');
128
128
  // Turn "internal:control=enter-frame >> nth=0" into "nth=0 >> internal:control=enter-frame"
129
129
  // because these are swapped in locators vs selectors.
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.buildFullSelector = buildFullSelector;
7
+ exports.toKeyboardModifiers = toKeyboardModifiers;
8
+ exports.traceParamsForAction = traceParamsForAction;
9
+ /**
10
+ * Copyright (c) Microsoft Corporation.
11
+ *
12
+ * Licensed under the Apache License, Version 2.0 (the "License");
13
+ * you may not use this file except in compliance with the License.
14
+ * You may obtain a copy of the License at
15
+ *
16
+ * http://www.apache.org/licenses/LICENSE-2.0
17
+ *
18
+ * Unless required by applicable law or agreed to in writing, software
19
+ * distributed under the License is distributed on an "AS IS" BASIS,
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ * See the License for the specific language governing permissions and
22
+ * limitations under the License.
23
+ */
24
+
25
+ function buildFullSelector(framePath, selector) {
26
+ return [...framePath, selector].join(' >> internal:control=enter-frame >> ');
27
+ }
28
+ function traceParamsForAction(actionInContext) {
29
+ const {
30
+ action
31
+ } = actionInContext;
32
+ switch (action.name) {
33
+ case 'navigate':
34
+ {
35
+ const params = {
36
+ url: action.url
37
+ };
38
+ return {
39
+ method: 'goto',
40
+ params
41
+ };
42
+ }
43
+ case 'openPage':
44
+ case 'closePage':
45
+ throw new Error('Not reached');
46
+ }
47
+ const selector = buildFullSelector(actionInContext.frame.framePath, action.selector);
48
+ switch (action.name) {
49
+ case 'click':
50
+ {
51
+ const params = {
52
+ selector,
53
+ strict: true,
54
+ modifiers: toKeyboardModifiers(action.modifiers),
55
+ button: action.button,
56
+ clickCount: action.clickCount,
57
+ position: action.position
58
+ };
59
+ return {
60
+ method: 'click',
61
+ params
62
+ };
63
+ }
64
+ case 'press':
65
+ {
66
+ const params = {
67
+ selector,
68
+ strict: true,
69
+ key: [...toKeyboardModifiers(action.modifiers), action.key].join('+')
70
+ };
71
+ return {
72
+ method: 'press',
73
+ params
74
+ };
75
+ }
76
+ case 'fill':
77
+ {
78
+ const params = {
79
+ selector,
80
+ strict: true,
81
+ value: action.text
82
+ };
83
+ return {
84
+ method: 'fill',
85
+ params
86
+ };
87
+ }
88
+ case 'setInputFiles':
89
+ {
90
+ const params = {
91
+ selector,
92
+ strict: true,
93
+ localPaths: action.files
94
+ };
95
+ return {
96
+ method: 'setInputFiles',
97
+ params
98
+ };
99
+ }
100
+ case 'check':
101
+ {
102
+ const params = {
103
+ selector,
104
+ strict: true
105
+ };
106
+ return {
107
+ method: 'check',
108
+ params
109
+ };
110
+ }
111
+ case 'uncheck':
112
+ {
113
+ const params = {
114
+ selector,
115
+ strict: true
116
+ };
117
+ return {
118
+ method: 'uncheck',
119
+ params
120
+ };
121
+ }
122
+ case 'select':
123
+ {
124
+ const params = {
125
+ selector,
126
+ strict: true,
127
+ options: action.options.map(option => ({
128
+ value: option
129
+ }))
130
+ };
131
+ return {
132
+ method: 'selectOption',
133
+ params
134
+ };
135
+ }
136
+ case 'assertChecked':
137
+ {
138
+ const params = {
139
+ selector: action.selector,
140
+ expression: 'to.be.checked',
141
+ isNot: !action.checked
142
+ };
143
+ return {
144
+ method: 'expect',
145
+ params
146
+ };
147
+ }
148
+ case 'assertText':
149
+ {
150
+ const params = {
151
+ selector,
152
+ expression: 'to.have.text',
153
+ expectedText: [],
154
+ isNot: false
155
+ };
156
+ return {
157
+ method: 'expect',
158
+ params
159
+ };
160
+ }
161
+ case 'assertValue':
162
+ {
163
+ const params = {
164
+ selector,
165
+ expression: 'to.have.value',
166
+ expectedValue: undefined,
167
+ isNot: false
168
+ };
169
+ return {
170
+ method: 'expect',
171
+ params
172
+ };
173
+ }
174
+ case 'assertVisible':
175
+ {
176
+ const params = {
177
+ selector,
178
+ expression: 'to.be.visible',
179
+ isNot: false
180
+ };
181
+ return {
182
+ method: 'expect',
183
+ params
184
+ };
185
+ }
186
+ }
187
+ }
188
+ function toKeyboardModifiers(modifiers) {
189
+ const result = [];
190
+ if (modifiers & 1) result.push('Alt');
191
+ if (modifiers & 2) result.push('ControlOrMeta');
192
+ if (modifiers & 4) result.push('ControlOrMeta');
193
+ if (modifiers & 8) result.push('Shift');
194
+ return result;
195
+ }