@seleniumhq/side-runtime 4.0.0-alpha.9 → 4.0.2

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