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