@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.
- 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/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 +5 -4
- package/dist/playback-tree/command-node.d.ts.map +1 -1
- package/dist/playback-tree/command-node.js +81 -29
- 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 +16 -12
- package/dist/playback.d.ts.map +1 -1
- package/dist/playback.js +64 -33
- 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 -29
- 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 +39 -45
- package/dist/webdriver.d.ts.map +1 -1
- package/dist/webdriver.js +283 -222
- package/dist/webdriver.js.map +1 -1
- 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
|
|
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,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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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.
|
|
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
|
|
130
|
-
|
|
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.
|
|
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, _,
|
|
258
|
-
const
|
|
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, _,
|
|
279
|
-
const
|
|
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, _,
|
|
304
|
-
const
|
|
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, _,
|
|
341
|
-
const
|
|
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, _,
|
|
348
|
-
const
|
|
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
|
|
386
|
-
|
|
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
|
|
390
|
-
|
|
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.
|
|
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
|
-
|
|
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, _,
|
|
521
|
-
const
|
|
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, _,
|
|
527
|
-
const
|
|
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
|
|
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
|
|
774
|
+
async elementIsLocated(locator, ..._fallbacks) {
|
|
660
775
|
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;
|
|
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
|
|
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;
|
|
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)
|