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