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