@seleniumhq/side-runtime 4.0.0-alpha.4 → 4.0.0-alpha.41

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 (96) hide show
  1. package/dist/__tests__/callstack.spec.d.ts +2 -0
  2. package/dist/__tests__/callstack.spec.d.ts.map +1 -0
  3. package/dist/__tests__/callstack.spec.js +63 -0
  4. package/dist/__tests__/callstack.spec.js.map +1 -0
  5. package/dist/__tests__/integration/playback-webdriver.spec.d.ts +2 -0
  6. package/dist/__tests__/integration/playback-webdriver.spec.d.ts.map +1 -0
  7. package/dist/__tests__/integration/playback-webdriver.spec.js +249 -0
  8. package/dist/__tests__/integration/playback-webdriver.spec.js.map +1 -0
  9. package/dist/__tests__/playback-tree/command-leveler.spec.d.ts +2 -0
  10. package/dist/__tests__/playback-tree/command-leveler.spec.d.ts.map +1 -0
  11. package/dist/__tests__/playback-tree/command-leveler.spec.js +69 -0
  12. package/dist/__tests__/playback-tree/command-leveler.spec.js.map +1 -0
  13. package/dist/__tests__/playback-tree/command-node.spec.d.ts +2 -0
  14. package/dist/__tests__/playback-tree/command-node.spec.d.ts.map +1 -0
  15. package/dist/__tests__/playback-tree/command-node.spec.js +232 -0
  16. package/dist/__tests__/playback-tree/command-node.spec.js.map +1 -0
  17. package/dist/__tests__/playback-tree/playback-tree.spec.d.ts +2 -0
  18. package/dist/__tests__/playback-tree/playback-tree.spec.d.ts.map +1 -0
  19. package/dist/__tests__/playback-tree/playback-tree.spec.js +463 -0
  20. package/dist/__tests__/playback-tree/playback-tree.spec.js.map +1 -0
  21. package/dist/__tests__/playback-tree/syntax-validation.spec.d.ts +2 -0
  22. package/dist/__tests__/playback-tree/syntax-validation.spec.d.ts.map +1 -0
  23. package/dist/__tests__/playback-tree/syntax-validation.spec.js +224 -0
  24. package/dist/__tests__/playback-tree/syntax-validation.spec.js.map +1 -0
  25. package/dist/__tests__/playback.spec.d.ts +2 -0
  26. package/dist/__tests__/playback.spec.d.ts.map +1 -0
  27. package/dist/__tests__/playback.spec.js +2161 -0
  28. package/dist/__tests__/playback.spec.js.map +1 -0
  29. package/dist/__tests__/preprocessors.spec.d.ts +2 -0
  30. package/dist/__tests__/preprocessors.spec.d.ts.map +1 -0
  31. package/dist/__tests__/preprocessors.spec.js +141 -0
  32. package/dist/__tests__/preprocessors.spec.js.map +1 -0
  33. package/dist/__tests__/util/FakeExecutor.d.ts +32 -0
  34. package/dist/__tests__/util/FakeExecutor.d.ts.map +1 -0
  35. package/dist/__tests__/util/FakeExecutor.js +81 -0
  36. package/dist/__tests__/util/FakeExecutor.js.map +1 -0
  37. package/dist/__tests__/util/JestFakeExecutor.d.ts +32 -0
  38. package/dist/__tests__/util/JestFakeExecutor.d.ts.map +1 -0
  39. package/dist/__tests__/util/JestFakeExecutor.js +79 -0
  40. package/dist/__tests__/util/JestFakeExecutor.js.map +1 -0
  41. package/dist/__tests__/utils.spec.d.ts +2 -0
  42. package/dist/__tests__/utils.spec.d.ts.map +1 -0
  43. package/dist/__tests__/utils.spec.js +40 -0
  44. package/dist/__tests__/utils.spec.js.map +1 -0
  45. package/dist/__tests__/webdriver.spec.d.ts +2 -0
  46. package/dist/__tests__/webdriver.spec.d.ts.map +1 -0
  47. package/dist/__tests__/webdriver.spec.js +522 -0
  48. package/dist/__tests__/webdriver.spec.js.map +1 -0
  49. package/dist/callstack.d.ts +1 -1
  50. package/dist/callstack.d.ts.map +1 -1
  51. package/dist/playback-tree/command-leveler.d.ts +2 -2
  52. package/dist/playback-tree/command-leveler.d.ts.map +1 -1
  53. package/dist/playback-tree/command-leveler.js +4 -2
  54. package/dist/playback-tree/command-leveler.js.map +1 -1
  55. package/dist/playback-tree/command-node.d.ts +4 -4
  56. package/dist/playback-tree/command-node.d.ts.map +1 -1
  57. package/dist/playback-tree/command-node.js +73 -39
  58. package/dist/playback-tree/command-node.js.map +1 -1
  59. package/dist/playback-tree/commands.d.ts +12 -9
  60. package/dist/playback-tree/commands.d.ts.map +1 -1
  61. package/dist/playback-tree/commands.js +22 -14
  62. package/dist/playback-tree/commands.js.map +1 -1
  63. package/dist/playback-tree/index.d.ts +1 -1
  64. package/dist/playback-tree/index.d.ts.map +1 -1
  65. package/dist/playback-tree/index.js +5 -2
  66. package/dist/playback-tree/index.js.map +1 -1
  67. package/dist/playback-tree/syntax-validation.d.ts.map +1 -1
  68. package/dist/playback-tree/syntax-validation.js +4 -2
  69. package/dist/playback-tree/syntax-validation.js.map +1 -1
  70. package/dist/playback.d.ts +14 -12
  71. package/dist/playback.d.ts.map +1 -1
  72. package/dist/playback.js +59 -29
  73. package/dist/playback.js.map +1 -1
  74. package/dist/plugins.d.ts +4 -3
  75. package/dist/plugins.d.ts.map +1 -1
  76. package/dist/plugins.js +28 -9
  77. package/dist/plugins.js.map +1 -1
  78. package/dist/preprocessors.d.ts +2 -2
  79. package/dist/preprocessors.d.ts.map +1 -1
  80. package/dist/preprocessors.js +12 -28
  81. package/dist/preprocessors.js.map +1 -1
  82. package/dist/recording-syncronizer-webdriver.d.ts +3 -3
  83. package/dist/recording-syncronizer.d.ts +4 -3
  84. package/dist/recording-syncronizer.d.ts.map +1 -1
  85. package/dist/recording-syncronizer.js +1 -1
  86. package/dist/recording-syncronizer.js.map +1 -1
  87. package/dist/types.d.ts +25 -27
  88. package/dist/types.d.ts.map +1 -1
  89. package/dist/variables.d.ts.map +1 -1
  90. package/dist/variables.js +6 -0
  91. package/dist/variables.js.map +1 -1
  92. package/dist/webdriver.d.ts +36 -44
  93. package/dist/webdriver.d.ts.map +1 -1
  94. package/dist/webdriver.js +264 -218
  95. package/dist/webdriver.js.map +1 -1
  96. package/package.json +16 -14
package/dist/webdriver.js CHANGED
@@ -23,20 +23,15 @@ const selenium_webdriver_1 = __importDefault(require("selenium-webdriver"));
23
23
  const utils_1 = require("./utils");
24
24
  const preprocessors_1 = require("./preprocessors");
25
25
  const errors_1 = require("./errors");
26
- const { By, Condition, until, Key, WebElement, WebElementCondition, WebElementPromise, } = selenium_webdriver_1.default;
27
- const { TimeoutError } = selenium_webdriver_1.default.error;
28
- const POLL_TIMEOUT = 50;
26
+ const util_1 = require("util");
27
+ const { version: SeleniumWebdriverVersion, } = require('selenium-webdriver/package.json');
28
+ const { By, Condition, until, Key, WebElementCondition } = selenium_webdriver_1.default;
29
29
  const DEFAULT_CAPABILITIES = {
30
30
  browserName: 'chrome',
31
31
  };
32
32
  const state = Symbol('state');
33
- const defaultWindowAPI = {
34
- setWindowSize: async (executor, width, height) => {
35
- await executor.driver.manage().window().setRect({ width, height });
36
- },
37
- };
38
33
  class WebDriverExecutor {
39
- constructor({ customCommands = {}, disableCodeExportCompat = false, driver, capabilities, server, hooks = {}, implicitWait, windowAPI = defaultWindowAPI, }) {
34
+ constructor({ customCommands = {}, disableCodeExportCompat = false, driver, capabilities, server, hooks = {}, implicitWait, }) {
40
35
  if (driver) {
41
36
  this.driver = driver;
42
37
  }
@@ -50,9 +45,8 @@ class WebDriverExecutor {
50
45
  this.hooks = hooks;
51
46
  this.waitForNewWindow = this.waitForNewWindow.bind(this);
52
47
  this.customCommands = customCommands;
53
- this.windowAPI = windowAPI;
54
48
  }
55
- async init({ baseUrl, logger, variables }) {
49
+ async init({ baseUrl, debug, logger, variables, }) {
56
50
  this.baseUrl = baseUrl;
57
51
  this.logger = logger;
58
52
  this.variables = variables;
@@ -61,12 +55,56 @@ class WebDriverExecutor {
61
55
  const { browserName, ...capabilities } = this
62
56
  .capabilities;
63
57
  this.logger.info('Building driver for ' + browserName);
64
- this.driver = await new selenium_webdriver_1.default.Builder()
65
- .withCapabilities(capabilities)
66
- .usingServer(this.server)
67
- .forBrowser(browserName)
68
- .build();
69
- this.logger.info('Driver has been built for ' + browserName);
58
+ debug &&
59
+ this.logger.info('Driver attributes:' +
60
+ (0, util_1.inspect)({
61
+ capabilities,
62
+ server: this.server,
63
+ browserName,
64
+ }));
65
+ let driver = new selenium_webdriver_1.default.Builder().withCapabilities(capabilities);
66
+ if (this.server) {
67
+ driver = driver.usingServer(this.server);
68
+ }
69
+ try {
70
+ this.driver = await driver.forBrowser(browserName).build();
71
+ this.logger.info('Driver has been built for ' + browserName);
72
+ }
73
+ catch (e) {
74
+ if (debug) {
75
+ const driverCode = 'const driver = new webdriver.Builder()' +
76
+ `.withCapabilities(${JSON.stringify(capabilities)})` +
77
+ (this.server ? `.usingServer('${this.server}')` : '') +
78
+ `.forBrowser('${browserName}').build()`;
79
+ console.error(`
80
+ Failed to build driver for ${browserName}
81
+ Supplied capabilities: ${JSON.stringify(capabilities)}
82
+ Server: ${this.server || 'none'}
83
+ Error: ${e}
84
+
85
+ OS: ${process.platform}
86
+ Node: ${process.version}
87
+ Selenium-Webdriver: ${SeleniumWebdriverVersion}
88
+
89
+ This is breaking at the boundary of the following code in selenium-webdriver:
90
+
91
+ // BEGIN SELENIUM-WEBDRIVER CODE
92
+ const webdriver = require('selenium-webdriver')
93
+ ${driverCode}
94
+ // END SELENIUM-WEBDRIVER CODE
95
+
96
+ To ensure the bug is in selenium IDE, please attempt to run the above code in a script or node REPL.
97
+ You may have to npm install selenium-webdriver first.
98
+
99
+ If you are unable to proceed further, please raise a bug here:
100
+ https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=I-defect%2Cneeds-triaging&projects=&template=bug-report.yml&title=%5B%F0%9F%90%9B+Bug%5D%3A+
101
+
102
+ If this code works in selenium-webdriver, but not the IDE or side-runner, please raise a bug here:
103
+ https://github.com/SeleniumHQ/selenium-ide/issues/new?assignees=&labels=&projects=&template=bug.md
104
+ `);
105
+ }
106
+ throw e;
107
+ }
70
108
  }
71
109
  this.initialized = true;
72
110
  }
@@ -76,7 +114,8 @@ class WebDriverExecutor {
76
114
  }
77
115
  }
78
116
  async cleanup() {
79
- if (this.initialized) {
117
+ // await this.cancel()
118
+ if (this.driver) {
80
119
  await this.driver.quit();
81
120
  // @ts-expect-error
82
121
  this.driver = undefined;
@@ -92,18 +131,25 @@ class WebDriverExecutor {
92
131
  if (!command) {
93
132
  return 'skip';
94
133
  }
95
- const upperCase = command.charAt(0).toUpperCase() + command.slice(1);
96
- const func = 'do' + upperCase;
134
+ if (this.customCommands[command]) {
135
+ return command;
136
+ }
137
+ const func = this.nameTransform(command);
97
138
  // @ts-expect-error The functions can be overridden by custom commands and stuff
98
139
  if (!this[func]) {
99
140
  throw new Error(`Unknown command ${command}`);
100
141
  }
101
142
  return func;
102
143
  }
144
+ nameTransform(command) {
145
+ const upperCase = command.charAt(0).toUpperCase() + command.slice(1);
146
+ return 'do' + upperCase;
147
+ }
103
148
  async executeHook(hook, ...args) {
104
149
  const fn = this.hooks[hook];
105
150
  if (!fn)
106
151
  return;
152
+ // @ts-expect-error it's okay, this shape is fine
107
153
  await fn.apply(this, args);
108
154
  }
109
155
  async beforeCommand(commandObject) {
@@ -115,7 +161,7 @@ class WebDriverExecutor {
115
161
  async afterCommand(commandObject) {
116
162
  this.cancellable = undefined;
117
163
  if (commandObject.opensWindow) {
118
- const handle = await this.wait(this.waitForNewWindow(), commandObject.windowTimeout);
164
+ const handle = await this.waitForNewWindow(commandObject.windowTimeout);
119
165
  this.variables.set(commandObject.windowHandleName, handle);
120
166
  await this.executeHook('onWindowAppeared', {
121
167
  command: commandObject,
@@ -125,9 +171,26 @@ class WebDriverExecutor {
125
171
  }
126
172
  await this.executeHook('onAfterCommand', { command: commandObject });
127
173
  }
128
- async waitForNewWindow() {
129
- const currentHandles = await this.driver.getAllWindowHandles();
130
- return currentHandles.find((handle) => !this[state].openedWindows.includes(handle));
174
+ async waitForNewWindow(timeout = 2000) {
175
+ const finder = new Promise((resolve) => {
176
+ const start = Date.now();
177
+ const findHandle = this.withCancel(async () => {
178
+ if (Date.now() - start > timeout) {
179
+ resolve(undefined);
180
+ return;
181
+ }
182
+ const currentHandles = await this.driver.getAllWindowHandles();
183
+ const newHandle = currentHandles.find((handle) => !this[state].openedWindows.includes(handle));
184
+ if (newHandle) {
185
+ resolve(newHandle);
186
+ return;
187
+ }
188
+ // cant find, wait next time.
189
+ setTimeout(findHandle, 200);
190
+ });
191
+ findHandle();
192
+ });
193
+ return this.driver.wait(finder, timeout);
131
194
  }
132
195
  registerCommand(commandName, fn) {
133
196
  // @ts-expect-error
@@ -143,7 +206,7 @@ class WebDriverExecutor {
143
206
  }
144
207
  async doSetWindowSize(widthXheight) {
145
208
  const [width, height] = widthXheight.split('x').map((v) => parseInt(v));
146
- await this.windowAPI.setWindowSize(this, width, height);
209
+ await this.driver.manage().window().setRect({ width, height });
147
210
  }
148
211
  async doSelectWindow(handleLocator) {
149
212
  const prefix = 'handle=';
@@ -206,12 +269,9 @@ class WebDriverExecutor {
206
269
  await targetLocator.frame(element);
207
270
  }
208
271
  }
209
- async doSubmit() {
210
- throw new Error('"submit" is not a supported command in Selenium WebDriver. Please re-record the step.');
211
- }
212
272
  // mouse commands
213
273
  async doAddSelection(locator, optionLocator, commandObject = {}) {
214
- const element = await this.waitForElement(locator, commandObject.targetFallback);
274
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
215
275
  const option = await element.findElement(parseOptionLocator(optionLocator));
216
276
  const selections = (await this.driver.executeScript('return arguments[0].selectedOptions', element));
217
277
  if (!(await findElement(selections, option))) {
@@ -219,7 +279,7 @@ class WebDriverExecutor {
219
279
  }
220
280
  }
221
281
  async doRemoveSelection(locator, optionLocator, commandObject = {}) {
222
- const element = await this.waitForElement(locator, commandObject.targetFallback);
282
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
223
283
  if (!(await element.getAttribute('multiple'))) {
224
284
  throw new Error('Given element is not a multiple select type element');
225
285
  }
@@ -230,37 +290,38 @@ class WebDriverExecutor {
230
290
  }
231
291
  }
232
292
  async doCheck(locator, _, commandObject = {}) {
233
- const element = await this.waitForElement(locator, commandObject.targetFallback);
293
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
234
294
  if (!(await element.isSelected())) {
235
295
  await element.click();
236
296
  }
237
297
  }
238
298
  async doUncheck(locator, _, commandObject = {}) {
239
- const element = await this.waitForElement(locator, commandObject.targetFallback);
299
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
240
300
  if (await element.isSelected()) {
241
301
  await element.click();
242
302
  }
243
303
  }
244
- async doClick(locator, _) {
245
- const element = await this.waitForElementVisible(locator, this.implicitWait);
304
+ async doClick(locator, _, commandObject = {}) {
305
+ const element = await this.waitForElementVisible(locator, this.implicitWait, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
246
306
  await element.click();
247
307
  }
248
308
  async doClickAt(locator, coordString, commandObject = {}) {
249
309
  const coords = parseCoordString(coordString);
250
- const element = await this.waitForElement(locator, commandObject.targetFallback);
310
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
251
311
  await this.driver
252
312
  .actions({ bridge: true })
253
313
  .move({ origin: element, ...coords })
254
314
  .click()
255
315
  .perform();
256
316
  }
257
- async doDoubleClick(locator, _, commandObject = {}) {
258
- const element = await this.waitForElement(locator, commandObject.targetFallback);
317
+ async doDoubleClick(locator, _, _commandObject) {
318
+ const commandObject = _commandObject || {};
319
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
259
320
  await this.driver.actions({ bridge: true }).doubleClick(element).perform();
260
321
  }
261
322
  async doDoubleClickAt(locator, coordString, commandObject = {}) {
262
323
  const coords = parseCoordString(coordString);
263
- const element = await this.waitForElement(locator, commandObject.targetFallback);
324
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
264
325
  await this.driver
265
326
  .actions({ bridge: true })
266
327
  .move({ origin: element, ...coords })
@@ -275,8 +336,9 @@ class WebDriverExecutor {
275
336
  .dragAndDrop(drag, drop)
276
337
  .perform();
277
338
  }
278
- async doMouseDown(locator, _, commandObject = {}) {
279
- const element = await this.waitForElement(locator, commandObject.targetFallback);
339
+ async doMouseDown(locator, _, _commandObject) {
340
+ const commandObject = _commandObject || {};
341
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
280
342
  await this.driver
281
343
  .actions({ bridge: true })
282
344
  .move({ origin: element })
@@ -285,7 +347,7 @@ class WebDriverExecutor {
285
347
  }
286
348
  async doMouseDownAt(locator, coordString, commandObject = {}) {
287
349
  const coords = parseCoordString(coordString);
288
- const element = await this.waitForElement(locator, commandObject.targetFallback);
350
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
289
351
  await this.driver
290
352
  .actions({ bridge: true })
291
353
  .move({ origin: element, ...coords })
@@ -294,18 +356,19 @@ class WebDriverExecutor {
294
356
  }
295
357
  async doMouseMoveAt(locator, coordString, commandObject = {}) {
296
358
  const coords = parseCoordString(coordString);
297
- const element = await this.waitForElement(locator, commandObject.targetFallback);
359
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
298
360
  await this.driver
299
361
  .actions({ bridge: true })
300
362
  .move({ origin: element, ...coords })
301
363
  .perform();
302
364
  }
303
- async doMouseOut(locator, _, commandObject = {}) {
304
- const element = await this.waitForElement(locator, commandObject.targetFallback);
365
+ async doMouseOut(locator, _, _commandObject) {
366
+ const commandObject = _commandObject || {};
367
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
305
368
  const [rect, vp] = await this.driver.executeScript('return [arguments[0].getBoundingClientRect(), {height: window.innerHeight, width: window.innerWidth}];', element);
306
369
  // try top
307
370
  if (rect.top > 0) {
308
- const y = -(rect.height / 2 + 1);
371
+ const y = Math.round(-(rect.height / 2 + 1));
309
372
  return await this.driver
310
373
  .actions({ bridge: true })
311
374
  .move({ origin: element, y })
@@ -313,7 +376,7 @@ class WebDriverExecutor {
313
376
  }
314
377
  // try right
315
378
  else if (vp.width > rect.right) {
316
- const x = rect.right / 2 + 1;
379
+ const x = Math.round(rect.right / 2 + 1);
317
380
  return await this.driver
318
381
  .actions({ bridge: true })
319
382
  .move({ origin: element, x })
@@ -321,7 +384,7 @@ class WebDriverExecutor {
321
384
  }
322
385
  // try bottom
323
386
  else if (vp.height > rect.bottom) {
324
- const y = rect.height / 2 + 1;
387
+ const y = Math.round(rect.height / 2 + 1);
325
388
  return await this.driver
326
389
  .actions({ bridge: true })
327
390
  .move({ origin: element, y })
@@ -329,7 +392,7 @@ class WebDriverExecutor {
329
392
  }
330
393
  // try left
331
394
  else if (rect.left > 0) {
332
- const x = -rect.right / 2;
395
+ const x = Math.round(-rect.right / 2);
333
396
  return await this.driver
334
397
  .actions({ bridge: true })
335
398
  .move({ origin: element, x })
@@ -337,15 +400,17 @@ class WebDriverExecutor {
337
400
  }
338
401
  throw new Error('Unable to perform mouse out as the element takes up the entire viewport');
339
402
  }
340
- async doMouseOver(locator, _, commandObject = {}) {
341
- const element = await this.waitForElement(locator, commandObject.targetFallback);
403
+ async doMouseOver(locator, _, _commandObject) {
404
+ const commandObject = _commandObject || {};
405
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
342
406
  await this.driver
343
407
  .actions({ bridge: true })
344
408
  .move({ origin: element })
345
409
  .perform();
346
410
  }
347
- async doMouseUp(locator, _, commandObject = {}) {
348
- const element = await this.waitForElement(locator, commandObject.targetFallback);
411
+ async doMouseUp(locator, _, _commandObject) {
412
+ const commandObject = _commandObject || {};
413
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
349
414
  await this.driver
350
415
  .actions({ bridge: true })
351
416
  .move({ origin: element })
@@ -354,7 +419,7 @@ class WebDriverExecutor {
354
419
  }
355
420
  async doMouseUpAt(locator, coordString, commandObject = {}) {
356
421
  const coords = parseCoordString(coordString);
357
- const element = await this.waitForElement(locator, commandObject.targetFallback);
422
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
358
423
  await this.driver
359
424
  .actions({ bridge: true })
360
425
  .move({ origin: element, ...coords })
@@ -362,53 +427,86 @@ class WebDriverExecutor {
362
427
  .perform();
363
428
  }
364
429
  async doSelect(locator, optionLocator, commandObject = {}) {
365
- const element = await this.waitForElement(locator, commandObject.targetFallback);
430
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
366
431
  const option = await element.findElement(parseOptionLocator(optionLocator));
367
432
  await option.click();
368
433
  }
434
+ async doSubmit(locator, _, _commandObject) {
435
+ const commandObject = _commandObject || {};
436
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
437
+ console.error(`
438
+ "submit" is not a good command in Selenium WebDriver. It's not supported by
439
+ all browsers and it's manually triggering an event, when it should really
440
+ be driven out of an interaction (click submit, hit enter, etc).
441
+ Please re-record the step using a "click" or "sendKeys" command instead.
442
+ `);
443
+ await element.submit();
444
+ }
369
445
  // keyboard commands
370
446
  async doEditContent(locator, value, commandObject = {}) {
371
- const element = await this.waitForElement(locator, commandObject.targetFallback);
447
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
372
448
  await this.driver.executeScript("if(arguments[0].contentEditable === 'true') {arguments[0].innerText = arguments[1]} else {throw new Error('Element is not content editable')}", element, value);
373
449
  }
374
450
  async doType(locator, value, commandObject = {}) {
375
- const element = await this.waitForElement(locator, commandObject.targetFallback);
451
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
376
452
  await element.clear();
377
453
  await element.sendKeys(value);
378
454
  }
379
455
  async doSendKeys(locator, value, commandObject = {}) {
380
- const element = await this.waitForElement(locator, commandObject.targetFallback);
456
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
381
457
  await element.sendKeys(...value);
382
458
  }
383
459
  // wait commands
384
460
  async doWaitForElementEditable(locator, timeout) {
385
- const element = await this.driver.findElement(parseLocator(locator));
386
- await this.wait(this.isElementEditable(element), parseInt(timeout), 'Timed out waiting for element to be editable');
461
+ const condition = new Condition('for element to be editable', async () => {
462
+ const element = await this.driver.findElement(parseLocator(locator));
463
+ if (!element) {
464
+ return null;
465
+ }
466
+ const isEditable = await this.isElementEditable(element);
467
+ return isEditable;
468
+ });
469
+ await this.driver.wait(condition, parseInt(timeout));
387
470
  }
388
471
  async doWaitForElementNotEditable(locator, timeout) {
389
- const element = await this.driver.findElement(parseLocator(locator));
390
- await this.wait(this.isElementEditable(element), parseInt(timeout), 'Timed out waiting for element to not be editable');
472
+ const condition = new Condition('for element to be editable', async () => {
473
+ const element = await this.driver.findElement(parseLocator(locator));
474
+ if (!element) {
475
+ return null;
476
+ }
477
+ const isEditable = await this.isElementEditable(element);
478
+ return !isEditable;
479
+ });
480
+ await this.driver.wait(condition, parseInt(timeout));
391
481
  }
392
- async doWaitForElementPresent(locator, timeout) {
393
- await this.wait(until.elementLocated(parseLocator(locator)), parseInt(timeout));
482
+ async doWaitForElementPresent(locator, timeout, commandObj = {}) {
483
+ const locatorCondition = new WebElementCondition('for element to be present', async () => await this.elementIsLocated(locator, commandObj.targetFallback, commandObj.targets, commandObj.fallbackTargets));
484
+ await this.driver.wait(locatorCondition, Number(timeout));
394
485
  }
395
486
  async doWaitForElementNotPresent(locator, timeout) {
396
487
  const parsedLocator = parseLocator(locator);
397
488
  const elements = await this.driver.findElements(parsedLocator);
398
489
  if (elements.length !== 0) {
399
- await this.wait(until.stalenessOf(elements[0]), parseInt(timeout));
490
+ const noElementPresentCondition = new Condition('for element to not be present', async () => {
491
+ const elements = await this.driver.findElements(parsedLocator);
492
+ return elements.length === 0;
493
+ });
494
+ await this.driver.wait(noElementPresentCondition, Number(timeout));
400
495
  }
401
496
  }
402
- async doWaitForElementVisible(locator, timeout) {
403
- await this.waitForElementVisible(locator, parseInt(timeout));
497
+ async doWaitForElementVisible(locator, timeout, commandObj = {}) {
498
+ await this.waitForElementVisible(locator, parseInt(timeout), commandObj.targetFallback);
404
499
  }
405
500
  async doWaitForElementNotVisible(locator, timeout) {
406
501
  const parsedLocator = parseLocator(locator);
407
502
  const elements = await this.driver.findElements(parsedLocator);
408
503
  if (elements.length > 0) {
409
- await this.wait(until.elementIsNotVisible(elements[0]), parseInt(timeout));
504
+ await this.driver.wait(until.elementIsNotVisible(elements[0]), parseInt(timeout));
410
505
  }
411
506
  }
507
+ async doWaitForText(locator, text, commandObj = {}) {
508
+ await this.waitForText(locator, text, commandObj.targetFallback);
509
+ }
412
510
  // script commands
413
511
  async doRunScript(script) {
414
512
  await this.driver.executeScript(script.script, ...script.argv);
@@ -467,7 +565,7 @@ class WebDriverExecutor {
467
565
  return Promise.resolve();
468
566
  }
469
567
  async doStoreText(locator, variable, commandObject = {}) {
470
- const element = await this.waitForElement(locator, commandObject.targetFallback);
568
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
471
569
  const text = await element.getText();
472
570
  this.variables.set(variable, text);
473
571
  }
@@ -476,7 +574,7 @@ class WebDriverExecutor {
476
574
  this.variables.set(variable, title);
477
575
  }
478
576
  async doStoreValue(locator, variable, commandObject = {}) {
479
- const element = await this.waitForElement(locator, commandObject.targetFallback);
577
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
480
578
  const value = await element.getAttribute('value');
481
579
  this.variables.set(variable, value);
482
580
  }
@@ -517,14 +615,16 @@ class WebDriverExecutor {
517
615
  "'");
518
616
  }
519
617
  }
520
- async doAssertEditable(locator, _, commandObject = {}) {
521
- const element = await this.waitForElement(locator, commandObject.targetFallback);
618
+ async doAssertEditable(locator, _, _commandObject) {
619
+ const commandObject = _commandObject || {};
620
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
522
621
  if (!(await this.isElementEditable(element))) {
523
622
  throw new errors_1.AssertionError('Element is not editable');
524
623
  }
525
624
  }
526
- async doAssertNotEditable(locator, _, commandObject = {}) {
527
- const element = await this.waitForElement(locator, commandObject.targetFallback);
625
+ async doAssertNotEditable(locator, _, _commandObject) {
626
+ const commandObject = _commandObject || {};
627
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
528
628
  if (await this.isElementEditable(element)) {
529
629
  throw new errors_1.AssertionError('Element is editable');
530
630
  }
@@ -556,21 +656,21 @@ class WebDriverExecutor {
556
656
  }
557
657
  }
558
658
  async doAssertText(locator, value, commandObject = {}) {
559
- const element = await this.waitForElement(locator, commandObject.targetFallback);
659
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
560
660
  const text = await element.getText();
561
661
  if (text !== value) {
562
662
  throw new errors_1.AssertionError("Actual value '" + text + "' did not match '" + value + "'");
563
663
  }
564
664
  }
565
665
  async doAssertNotText(locator, value, commandObject = {}) {
566
- const element = await this.waitForElement(locator, commandObject.targetFallback);
666
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
567
667
  const text = await element.getText();
568
668
  if (text === value) {
569
669
  throw new errors_1.AssertionError("Actual value '" + text + "' did match '" + value + "'");
570
670
  }
571
671
  }
572
672
  async doAssertValue(locator, value, commandObject = {}) {
573
- const element = await this.waitForElement(locator, commandObject.targetFallback);
673
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
574
674
  const elementValue = await element.getAttribute('value');
575
675
  if (elementValue !== value) {
576
676
  throw new errors_1.AssertionError("Actual value '" + elementValue + "' did not match '" + value + "'");
@@ -578,40 +678,40 @@ class WebDriverExecutor {
578
678
  }
579
679
  // not generally implemented
580
680
  async doAssertNotValue(locator, value, commandObject = {}) {
581
- const element = await this.waitForElement(locator, commandObject.targetFallback);
681
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
582
682
  const elementValue = await element.getAttribute('value');
583
683
  if (elementValue === value) {
584
684
  throw new errors_1.AssertionError("Actual value '" + elementValue + "' did match '" + value + "'");
585
685
  }
586
686
  }
587
687
  async doAssertChecked(locator, _, commandObject = {}) {
588
- const element = await this.waitForElement(locator, commandObject.targetFallback);
688
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
589
689
  if (!(await element.isSelected())) {
590
690
  throw new errors_1.AssertionError('Element is not checked, expected to be checked');
591
691
  }
592
692
  }
593
693
  async doAssertNotChecked(locator, _, commandObject = {}) {
594
- const element = await this.waitForElement(locator, commandObject.targetFallback);
694
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
595
695
  if (await element.isSelected()) {
596
696
  throw new errors_1.AssertionError('Element is checked, expected to be unchecked');
597
697
  }
598
698
  }
599
699
  async doAssertSelectedValue(locator, value, commandObject = {}) {
600
- const element = await this.waitForElement(locator, commandObject.targetFallback);
700
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
601
701
  const elementValue = await element.getAttribute('value');
602
702
  if (elementValue !== value) {
603
703
  throw new errors_1.AssertionError("Actual value '" + elementValue + "' did not match '" + value + "'");
604
704
  }
605
705
  }
606
706
  async doAssertNotSelectedValue(locator, value, commandObject = {}) {
607
- const element = await this.waitForElement(locator, commandObject.targetFallback);
707
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
608
708
  const elementValue = await element.getAttribute('value');
609
709
  if (elementValue === value) {
610
710
  throw new errors_1.AssertionError("Actual value '" + elementValue + "' did match '" + value + "'");
611
711
  }
612
712
  }
613
713
  async doAssertSelectedLabel(locator, label, commandObject = {}) {
614
- const element = await this.waitForElement(locator, commandObject.targetFallback);
714
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
615
715
  const selectedValue = await element.getAttribute('value');
616
716
  const selectedOption = await element.findElement(By.xpath(`option[@value="${selectedValue}"]`));
617
717
  const selectedOptionLabel = await selectedOption.getText();
@@ -624,7 +724,7 @@ class WebDriverExecutor {
624
724
  }
625
725
  }
626
726
  async doAssertNotSelectedLabel(locator, label, commandObject = {}) {
627
- const element = await this.waitForElement(locator, commandObject?.targetFallback);
727
+ const element = await this.waitForElement(locator, commandObject.targetFallback, commandObject.targets, commandObject.fallbackTargets);
628
728
  const selectedValue = await element.getAttribute('value');
629
729
  const selectedOption = await element.findElement(By.xpath(`option[@value="${selectedValue}"]`));
630
730
  const selectedOptionLabel = await selectedOption.getText();
@@ -638,7 +738,7 @@ class WebDriverExecutor {
638
738
  }
639
739
  async doEcho(string) {
640
740
  if (this.logger) {
641
- this.logger.log(`echo: ${string}`);
741
+ this.logger.info(`echo: ${string}`);
642
742
  }
643
743
  }
644
744
  async doPause(time) {
@@ -651,154 +751,82 @@ class WebDriverExecutor {
651
751
  throw new Error('`set speed` is not supported in this run mode');
652
752
  }
653
753
  async evaluateConditional(script) {
654
- const result = await this.driver.executeScript(`return (${script.script})`, ...script.argv);
754
+ const result = await this.driver.executeScript((0, preprocessors_1.interpolateScript)(`return (${script.script})`, this.variables).script, ...script.argv);
655
755
  return {
656
756
  value: !!result,
657
757
  };
658
758
  }
659
- async waitForElement(locator, fallback = []) {
759
+ async elementIsLocated(locator, ..._fallbacks) {
660
760
  const elementLocator = parseLocator(locator);
661
- try {
662
- return (await this.wait(until.elementLocated(elementLocator), this.implicitWait));
663
- }
664
- catch (err) {
665
- if (fallback) {
666
- for (let i = 0; i < fallback.length; i++) {
667
- try {
668
- let loc = parseLocator(fallback[i][0]);
669
- return await this.driver.findElement(loc);
670
- }
671
- catch (e) {
672
- // try the next one
673
- }
674
- }
675
- }
676
- throw err;
761
+ const matches = await this.driver.findElements(elementLocator);
762
+ if (matches.length > 0)
763
+ return matches[0];
764
+ const fallbacks = _fallbacks.filter(Boolean).flat();
765
+ for (let i = 0; i < fallbacks.length; i++) {
766
+ const loc = parseLocator(fallbacks[i][0]);
767
+ const fallbackMatches = await this.driver.findElements(loc);
768
+ if (fallbackMatches.length)
769
+ return fallbackMatches[0];
677
770
  }
771
+ return null;
772
+ }
773
+ withCancel(poller) {
774
+ let resolveCancel;
775
+ const cancelPromise = new Promise((res) => {
776
+ resolveCancel = res;
777
+ });
778
+ let cancelled = false;
779
+ this.cancellable = {
780
+ cancel: () => {
781
+ cancelled = true;
782
+ return cancelPromise;
783
+ },
784
+ };
785
+ return async () => {
786
+ if (cancelled) {
787
+ resolveCancel();
788
+ throw new Error('aborted');
789
+ }
790
+ return await poller();
791
+ };
792
+ }
793
+ async waitForElement(locator, ...fallbacks) {
794
+ const locatorCondition = new WebElementCondition('for element to be located', this.withCancel(async () => await this.elementIsLocated(locator, ...fallbacks)));
795
+ return await this.driver.wait(locatorCondition, this.implicitWait);
678
796
  }
679
797
  async isElementEditable(element) {
680
798
  const { enabled, readonly } = await this.driver.executeScript('return { enabled: !arguments[0].disabled, readonly: arguments[0].readOnly };', element);
681
799
  return enabled && !readonly;
682
800
  }
683
- async retryToAllowForIntermittency(locator, timeout) {
684
- const startTime = Date.now();
685
- const element = (await this.wait(until.elementLocated(parseLocator(locator)), timeout));
686
- const elapsed = Date.now() - startTime;
687
- await this.wait(until.elementIsVisible(element), timeout - elapsed);
688
- return element;
689
- }
690
- async waitForElementVisible(locator, timeout) {
691
- const startTime = Date.now();
692
- const element = (await this.wait(until.elementLocated(parseLocator(locator)), timeout));
693
- const elapsed = Date.now() - startTime;
694
- await this.wait(until.elementIsVisible(element), timeout - elapsed);
695
- return element;
696
- }
697
- async wait(condition, timeout = 0, message = '', pollTimeout = POLL_TIMEOUT) {
698
- if (typeof timeout !== 'number' || timeout < 0) {
699
- throw TypeError('timeout must be a number >= 0: ' + timeout);
700
- }
701
- if (typeof pollTimeout !== 'number' || pollTimeout < 0) {
702
- throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout);
703
- }
704
- if (isConditionPromiseLike(condition)) {
705
- return new Promise((resolve, reject) => {
706
- if (!timeout) {
707
- resolve(condition);
708
- return;
709
- }
710
- let start = Date.now();
711
- let timer = setTimeout(function () {
712
- timer = null;
713
- reject(new TimeoutError((message ? `${message}\n` : '') +
714
- 'Timed out waiting for promise to resolve after ' +
715
- (Date.now() - start) +
716
- 'ms'));
717
- }, timeout);
718
- const clearTimer = () => timer && clearTimeout(timer);
719
- condition.then(function (value) {
720
- clearTimer();
721
- resolve(value);
722
- }, function (error) {
723
- clearTimer();
724
- reject(error);
725
- });
726
- });
727
- }
728
- // @ts-expect-error
729
- let fn = condition;
730
- if (condition instanceof Condition) {
731
- message = message || condition.description();
732
- fn = condition.fn;
733
- }
734
- if (typeof fn !== 'function') {
735
- throw TypeError('Wait condition must be a promise-like object, function, or a ' +
736
- 'Condition object');
737
- }
738
- const { driver } = this;
739
- function evaluateCondition() {
740
- return new Promise((resolve, reject) => {
741
- try {
742
- resolve(fn(driver));
743
- }
744
- catch (ex) {
745
- reject(ex);
746
- }
747
- });
748
- }
749
- let result = new Promise((resolve, reject) => {
750
- const startTime = Date.now();
751
- let cancelled = false;
752
- let resolveCancel;
753
- const cancelPromise = new Promise((res) => {
754
- resolveCancel = res;
755
- });
756
- this.cancellable = {
757
- cancel: () => {
758
- cancelled = true;
759
- return cancelPromise;
760
- },
761
- };
762
- const pollCondition = async () => {
763
- evaluateCondition().then((value) => {
764
- const elapsed = Date.now() - startTime;
765
- if (cancelled) {
766
- resolveCancel();
767
- reject(new Error('Aborted by user'));
768
- this.cancellable = undefined;
769
- }
770
- else if (value) {
771
- resolve(value);
772
- this.cancellable = undefined;
773
- }
774
- else if (timeout && elapsed >= timeout) {
775
- reject(new TimeoutError((message ? `${message}\n` : '') +
776
- `Wait timed out after ${elapsed}ms`));
777
- this.cancellable = undefined;
778
- }
779
- else {
780
- setTimeout(pollCondition, pollTimeout);
781
- }
782
- }, reject);
783
- };
784
- pollCondition();
785
- });
786
- if (condition instanceof WebElementCondition) {
787
- result = new WebElementPromise(driver, result.then(function (value) {
788
- if (!(value instanceof WebElement)) {
789
- throw TypeError('WebElementCondition did not resolve to a WebElement: ' +
790
- Object.prototype.toString.call(value));
791
- }
792
- return value;
793
- }));
794
- }
795
- return result;
801
+ async waitForElementVisible(locator, timeout, ...fallbacks) {
802
+ const visibleCondition = new WebElementCondition('for element to be visible', this.withCancel(async () => {
803
+ const el = await this.elementIsLocated(locator, ...fallbacks);
804
+ if (!el)
805
+ return null;
806
+ try {
807
+ if (!(await el.isDisplayed()))
808
+ return null;
809
+ }
810
+ catch (e) {
811
+ return null;
812
+ }
813
+ return el;
814
+ }));
815
+ return await this.driver.wait(visibleCondition, timeout);
816
+ }
817
+ async waitForText(locator, text, fallback = []) {
818
+ const timeout = this.implicitWait;
819
+ const textCondition = new Condition('for text to be present in element', this.withCancel(async () => {
820
+ const el = await this.elementIsLocated(locator, fallback);
821
+ if (!el)
822
+ return null;
823
+ const elText = await el.getText();
824
+ return elText === text;
825
+ }));
826
+ await this.driver.wait(textCondition, timeout);
796
827
  }
797
828
  }
798
829
  exports.default = WebDriverExecutor;
799
- function isConditionPromiseLike(condition) {
800
- return condition && typeof condition.then === 'function';
801
- }
802
830
  WebDriverExecutor.prototype.doOpen = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, WebDriverExecutor.prototype.doOpen);
803
831
  WebDriverExecutor.prototype.doSetWindowSize = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, WebDriverExecutor.prototype.doSetWindowSize);
804
832
  WebDriverExecutor.prototype.doSelectWindow = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, WebDriverExecutor.prototype.doSelectWindow);
@@ -865,10 +893,28 @@ WebDriverExecutor.prototype.doAssert = (0, preprocessors_1.composePreprocessors)
865
893
  WebDriverExecutor.prototype.doAssertAlert = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, WebDriverExecutor.prototype.doAssertAlert);
866
894
  WebDriverExecutor.prototype.doAssertConfirmation = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, WebDriverExecutor.prototype.doAssertConfirmation);
867
895
  WebDriverExecutor.prototype.doAssertEditable = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, { targetFallback: (0, preprocessors_1.preprocessArray)(preprocessors_1.interpolateString) }, WebDriverExecutor.prototype.doAssertEditable);
896
+ WebDriverExecutor.prototype.doAssertElementPresent = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, WebDriverExecutor.prototype.doAssertElementPresent);
897
+ WebDriverExecutor.prototype.doAssertElementNotPresent = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, WebDriverExecutor.prototype.doAssertElementNotPresent);
868
898
  WebDriverExecutor.prototype.doAssertNotEditable = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, { targetFallback: (0, preprocessors_1.preprocessArray)(preprocessors_1.interpolateString) }, WebDriverExecutor.prototype.doAssertNotEditable);
869
899
  WebDriverExecutor.prototype.doAssertPrompt = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, WebDriverExecutor.prototype.doAssertPrompt);
900
+ WebDriverExecutor.prototype.doAssertSelectedLabel = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, preprocessors_1.interpolateString, { targetFallback: (0, preprocessors_1.preprocessArray)(preprocessors_1.interpolateString) }, WebDriverExecutor.prototype.doAssertSelectedLabel);
870
901
  WebDriverExecutor.prototype.doAssertText = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, preprocessors_1.interpolateString, WebDriverExecutor.prototype.doAssertText);
902
+ WebDriverExecutor.prototype.doAssertTitle = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, null, WebDriverExecutor.prototype.doAssertTitle);
903
+ WebDriverExecutor.prototype.doAssertValue = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, preprocessors_1.interpolateString, { targetFallback: (0, preprocessors_1.preprocessArray)(preprocessors_1.interpolateString) }, WebDriverExecutor.prototype.doAssertValue);
871
904
  WebDriverExecutor.prototype.doEcho = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, WebDriverExecutor.prototype.doEcho);
905
+ const waitCommands = [
906
+ 'doWaitForElementEditable',
907
+ 'doWaitForElementNotEditable',
908
+ 'doWaitForElementPresent',
909
+ 'doWaitForElementNotPresent',
910
+ 'doWaitForElementVisible',
911
+ 'doWaitForElementNotVisible',
912
+ 'doWaitForText',
913
+ ];
914
+ waitCommands.forEach((cmd) => {
915
+ // @ts-expect-error - Whatever who cares
916
+ WebDriverExecutor.prototype[cmd] = (0, preprocessors_1.composePreprocessors)(preprocessors_1.interpolateString, preprocessors_1.interpolateString, WebDriverExecutor.prototype[cmd]);
917
+ });
872
918
  function createVerifyCommands(Executor) {
873
919
  // @ts-expect-error
874
920
  Object.getOwnPropertyNames(Executor.prototype)