Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/selenium-webdriver/test/lib/until_test.js
2885 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
'use strict'
19
20
const assert = require('node:assert')
21
22
const By = require('selenium-webdriver/lib/by').By
23
const CommandName = require('selenium-webdriver/lib/command').Name
24
const error = require('selenium-webdriver/lib/error')
25
const until = require('selenium-webdriver/lib/until')
26
const webdriver = require('selenium-webdriver/lib/webdriver')
27
const WebElement = webdriver.WebElement
28
29
describe('until', function () {
30
let driver, executor
31
32
class TestExecutor {
33
constructor() {
34
this.handlers_ = {}
35
}
36
37
on(cmd, handler) {
38
this.handlers_[cmd] = handler
39
return this
40
}
41
42
execute(cmd) {
43
let self = this
44
return Promise.resolve().then(function () {
45
if (!self.handlers_[cmd.getName()]) {
46
throw new error.UnknownCommandError(cmd.getName())
47
}
48
return self.handlers_[cmd.getName()](cmd)
49
})
50
}
51
}
52
53
function fail(opt_msg) {
54
throw new assert.AssertionError({ message: opt_msg })
55
}
56
57
beforeEach(function setUp() {
58
executor = new TestExecutor()
59
driver = new webdriver.WebDriver('session-id', executor)
60
})
61
62
describe('ableToSwitchToFrame', function () {
63
it('failsFastForNonSwitchErrors', function () {
64
let e = Error('boom')
65
executor.on(CommandName.SWITCH_TO_FRAME, function () {
66
throw e
67
})
68
return driver.wait(until.ableToSwitchToFrame(0), 100).then(fail, (e2) => assert.strictEqual(e2, e))
69
})
70
71
const ELEMENT_ID = 'some-element-id'
72
const ELEMENT_INDEX = 1234
73
74
function onSwitchFrame(expectedId) {
75
if (typeof expectedId === 'string') {
76
expectedId = WebElement.buildId(expectedId)
77
} else {
78
assert.strictEqual(typeof expectedId, 'number', 'must be string or number')
79
}
80
return (cmd) => {
81
assert.deepStrictEqual(cmd.getParameter('id'), expectedId, 'frame ID not specified')
82
return true
83
}
84
}
85
86
it('byIndex', function () {
87
executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_INDEX))
88
return driver.wait(until.ableToSwitchToFrame(ELEMENT_INDEX), 100)
89
})
90
91
it('byWebElement', function () {
92
executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID))
93
94
var el = new webdriver.WebElement(driver, ELEMENT_ID)
95
return driver.wait(until.ableToSwitchToFrame(el), 100)
96
})
97
98
it('byWebElementPromise', function () {
99
executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID))
100
var el = new webdriver.WebElementPromise(driver, Promise.resolve(new webdriver.WebElement(driver, ELEMENT_ID)))
101
return driver.wait(until.ableToSwitchToFrame(el), 100)
102
})
103
104
it('byLocator', function () {
105
executor.on(CommandName.FIND_ELEMENTS, () => [WebElement.buildId(ELEMENT_ID)])
106
executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID))
107
return driver.wait(until.ableToSwitchToFrame(By.id('foo')), 100)
108
})
109
110
it('byLocator_elementNotInitiallyFound', function () {
111
let foundResponses = [[], [], [WebElement.buildId(ELEMENT_ID)]]
112
executor.on(CommandName.FIND_ELEMENTS, () => foundResponses.shift())
113
executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID))
114
115
return driver
116
.wait(until.ableToSwitchToFrame(By.id('foo')), 2000)
117
.then(() => assert.deepStrictEqual(foundResponses, []))
118
})
119
120
it('timesOutIfNeverAbletoSwitchFrames', function () {
121
var count = 0
122
executor.on(CommandName.SWITCH_TO_FRAME, function () {
123
count += 1
124
throw new error.NoSuchFrameError()
125
})
126
127
return driver.wait(until.ableToSwitchToFrame(0), 100).then(fail, function (e) {
128
assert.ok(count > 0)
129
assert.ok(e.message.startsWith('Waiting to be able to switch to frame'), 'Wrong message: ' + e.message)
130
})
131
})
132
})
133
134
describe('alertIsPresent', function () {
135
it('failsFastForNonAlertSwitchErrors', function () {
136
return driver.wait(until.alertIsPresent(), 100).then(fail, function (e) {
137
assert.ok(e instanceof error.UnknownCommandError)
138
assert.strictEqual(e.message, CommandName.GET_ALERT_TEXT)
139
})
140
})
141
142
it('waitsForAlert', function () {
143
var count = 0
144
executor
145
.on(CommandName.GET_ALERT_TEXT, function () {
146
if (count++ < 3) {
147
throw new error.NoSuchAlertError()
148
} else {
149
return true
150
}
151
})
152
.on(CommandName.DISMISS_ALERT, () => true)
153
154
return driver.wait(until.alertIsPresent(), 1000).then(function (alert) {
155
assert.strictEqual(count, 4)
156
return alert.dismiss()
157
})
158
})
159
160
// TODO: Remove once GeckoDriver doesn't throw this unwanted error.
161
// See https://github.com/SeleniumHQ/selenium/pull/2137
162
describe('workaround for GeckoDriver', function () {
163
it('doesNotFailWhenCannotConvertNullToObject', function () {
164
var count = 0
165
executor
166
.on(CommandName.GET_ALERT_TEXT, function () {
167
if (count++ < 3) {
168
throw new error.WebDriverError(`can't convert null to object`)
169
} else {
170
return true
171
}
172
})
173
.on(CommandName.DISMISS_ALERT, () => true)
174
175
return driver.wait(until.alertIsPresent(), 1000).then(function (alert) {
176
assert.strictEqual(count, 4)
177
return alert.dismiss()
178
})
179
})
180
181
it('keepsRaisingRegularWebdriverError', function () {
182
var webDriverError = new error.WebDriverError()
183
184
executor.on(CommandName.GET_ALERT_TEXT, function () {
185
throw webDriverError
186
})
187
188
return driver.wait(until.alertIsPresent(), 1000).then(
189
function () {
190
throw new Error('driver did not fail against WebDriverError')
191
},
192
function (error) {
193
assert.strictEqual(error, webDriverError)
194
},
195
)
196
})
197
})
198
})
199
200
it('testUntilTitleIs', function () {
201
var titles = ['foo', 'bar', 'baz']
202
executor.on(CommandName.GET_TITLE, () => titles.shift())
203
204
return driver.wait(until.titleIs('bar'), 3000).then(function () {
205
assert.deepStrictEqual(titles, ['baz'])
206
})
207
})
208
209
it('testUntilTitleContains', function () {
210
var titles = ['foo', 'froogle', 'google']
211
executor.on(CommandName.GET_TITLE, () => titles.shift())
212
213
return driver.wait(until.titleContains('oogle'), 3000).then(function () {
214
assert.deepStrictEqual(titles, ['google'])
215
})
216
})
217
218
it('testUntilTitleMatches', function () {
219
var titles = ['foo', 'froogle', 'aaaabc', 'aabbbc', 'google']
220
executor.on(CommandName.GET_TITLE, () => titles.shift())
221
222
return driver.wait(until.titleMatches(/^a{2,3}b+c$/), 3000).then(function () {
223
assert.deepStrictEqual(titles, ['google'])
224
})
225
})
226
227
it('testUntilUrlIs', function () {
228
var urls = ['http://www.foo.com', 'https://boo.com', 'http://docs.yes.com']
229
executor.on(CommandName.GET_CURRENT_URL, () => urls.shift())
230
231
return driver.wait(until.urlIs('https://boo.com'), 3000).then(function () {
232
assert.deepStrictEqual(urls, ['http://docs.yes.com'])
233
})
234
})
235
236
it('testUntilUrlContains', function () {
237
var urls = ['http://foo.com', 'https://groups.froogle.com', 'http://google.com']
238
executor.on(CommandName.GET_CURRENT_URL, () => urls.shift())
239
240
return driver.wait(until.urlContains('oogle.com'), 3000).then(function () {
241
assert.deepStrictEqual(urls, ['http://google.com'])
242
})
243
})
244
245
it('testUntilUrlMatches', function () {
246
var urls = ['foo', 'froogle', 'aaaabc', 'aabbbc', 'google']
247
executor.on(CommandName.GET_CURRENT_URL, () => urls.shift())
248
249
return driver.wait(until.urlMatches(/^a{2,3}b+c$/), 3000).then(function () {
250
assert.deepStrictEqual(urls, ['google'])
251
})
252
})
253
254
it('testUntilElementLocated', function () {
255
var responses = [[], [WebElement.buildId('abc123'), WebElement.buildId('foo')], ['end']]
256
executor.on(CommandName.FIND_ELEMENTS, () => responses.shift())
257
258
let element = driver.wait(until.elementLocated(By.id('quux')), 2000)
259
assert.ok(element instanceof webdriver.WebElementPromise)
260
return element.getId().then(function (id) {
261
assert.deepStrictEqual(responses, [['end']])
262
assert.strictEqual(id, 'abc123')
263
})
264
})
265
266
describe('untilElementLocated, elementNeverFound', function () {
267
function runNoElementFoundTest(locator, locatorStr) {
268
executor.on(CommandName.FIND_ELEMENTS, () => [])
269
270
function expectedFailure() {
271
fail('expected condition to timeout')
272
}
273
274
return driver.wait(until.elementLocated(locator), 100).then(expectedFailure, function (error) {
275
var expected = 'Waiting for element to be located ' + locatorStr
276
var lines = error.message.split(/\n/, 2)
277
assert.strictEqual(lines[0], expected)
278
279
let regex = /^Wait timed out after \d+ms$/
280
assert.ok(regex.test(lines[1]), `Lines <${lines[1]}> does not match ${regex}`)
281
})
282
}
283
284
it('byLocator', function () {
285
return runNoElementFoundTest(By.id('quux'), 'By(css selector, *[id="quux"])')
286
})
287
288
it('byHash', function () {
289
return runNoElementFoundTest({ id: 'quux' }, 'By(css selector, *[id="quux"])')
290
})
291
292
it('byFunction', function () {
293
return runNoElementFoundTest(function () {}, 'by function()')
294
})
295
})
296
297
it('testUntilElementsLocated', function () {
298
var responses = [[], [WebElement.buildId('abc123'), WebElement.buildId('foo')], ['end']]
299
executor.on(CommandName.FIND_ELEMENTS, () => responses.shift())
300
301
return driver
302
.wait(until.elementsLocated(By.id('quux')), 2000)
303
.then(function (els) {
304
return Promise.all(els.map((e) => e.getId()))
305
})
306
.then(function (ids) {
307
assert.deepStrictEqual(responses, [['end']])
308
assert.strictEqual(ids.length, 2)
309
assert.strictEqual(ids[0], 'abc123')
310
assert.strictEqual(ids[1], 'foo')
311
})
312
})
313
314
describe('untilElementsLocated, noElementsFound', function () {
315
function runNoElementsFoundTest(locator, locatorStr) {
316
executor.on(CommandName.FIND_ELEMENTS, () => [])
317
318
function expectedFailure() {
319
fail('expected condition to timeout')
320
}
321
322
return driver.wait(until.elementsLocated(locator), 100).then(expectedFailure, function (error) {
323
var expected = 'Waiting for at least one element to be located ' + locatorStr
324
var lines = error.message.split(/\n/, 2)
325
assert.strictEqual(lines[0], expected)
326
327
let regex = /^Wait timed out after \d+ms$/
328
assert.ok(regex.test(lines[1]), `Lines <${lines[1]}> does not match ${regex}`)
329
})
330
}
331
332
it('byLocator', function () {
333
return runNoElementsFoundTest(By.id('quux'), 'By(css selector, *[id="quux"])')
334
})
335
336
it('byHash', function () {
337
return runNoElementsFoundTest({ id: 'quux' }, 'By(css selector, *[id="quux"])')
338
})
339
340
it('byFunction', function () {
341
return runNoElementsFoundTest(function () {}, 'by function()')
342
})
343
})
344
345
it('testUntilStalenessOf', function () {
346
let count = 0
347
executor.on(CommandName.GET_ELEMENT_TAG_NAME, function () {
348
while (count < 3) {
349
count += 1
350
return 'body'
351
}
352
throw new error.StaleElementReferenceError('now stale')
353
})
354
355
var el = new webdriver.WebElement(driver, { ELEMENT: 'foo' })
356
return driver.wait(until.stalenessOf(el), 2000).then(() => assert.strictEqual(count, 3))
357
})
358
359
describe('element state conditions', function () {
360
function runElementStateTest(predicate, command, responses, _var_args) {
361
let original = new webdriver.WebElement(driver, 'foo')
362
let predicateArgs = [original]
363
if (arguments.length > 3) {
364
predicateArgs = predicateArgs.concat(arguments[1])
365
command = arguments[2]
366
responses = arguments[3]
367
}
368
369
assert.ok(responses.length > 1)
370
371
responses = responses.concat(['end'])
372
executor.on(command, () => responses.shift())
373
374
let result = driver.wait(predicate.apply(null, predicateArgs), 2000)
375
assert.ok(result instanceof webdriver.WebElementPromise)
376
return result
377
.then(function (value) {
378
assert.ok(value instanceof webdriver.WebElement)
379
assert.ok(!(value instanceof webdriver.WebElementPromise))
380
return value.getId()
381
})
382
.then(function (id) {
383
assert.strictEqual('foo', id)
384
assert.deepStrictEqual(responses, ['end'])
385
})
386
}
387
388
it('elementIsVisible', function () {
389
return runElementStateTest(until.elementIsVisible, CommandName.IS_ELEMENT_DISPLAYED, [false, false, true])
390
})
391
392
it('elementIsNotVisible', function () {
393
return runElementStateTest(until.elementIsNotVisible, CommandName.IS_ELEMENT_DISPLAYED, [true, true, false])
394
})
395
396
it('elementIsEnabled', function () {
397
return runElementStateTest(until.elementIsEnabled, CommandName.IS_ELEMENT_ENABLED, [false, false, true])
398
})
399
400
it('elementIsDisabled', function () {
401
return runElementStateTest(until.elementIsDisabled, CommandName.IS_ELEMENT_ENABLED, [true, true, false])
402
})
403
404
it('elementIsSelected', function () {
405
return runElementStateTest(until.elementIsSelected, CommandName.IS_ELEMENT_SELECTED, [false, false, true])
406
})
407
408
it('elementIsNotSelected', function () {
409
return runElementStateTest(until.elementIsNotSelected, CommandName.IS_ELEMENT_SELECTED, [true, true, false])
410
})
411
412
it('elementTextIs', function () {
413
return runElementStateTest(until.elementTextIs, 'foobar', CommandName.GET_ELEMENT_TEXT, [
414
'foo',
415
'fooba',
416
'foobar',
417
])
418
})
419
420
it('elementTextContains', function () {
421
return runElementStateTest(until.elementTextContains, 'bar', CommandName.GET_ELEMENT_TEXT, [
422
'foo',
423
'foobaz',
424
'foobarbaz',
425
])
426
})
427
428
it('elementTextMatches', function () {
429
return runElementStateTest(until.elementTextMatches, /fo+bar{3}/, CommandName.GET_ELEMENT_TEXT, [
430
'foo',
431
'foobar',
432
'fooobarrr',
433
])
434
})
435
})
436
437
describe('WebElementCondition', function () {
438
it('fails if wait completes with a non-WebElement value', function () {
439
let result = driver.wait(new webdriver.WebElementCondition('testing', () => 123), 1000)
440
441
return result.then(
442
() => assert.fail('expected to fail'),
443
function (e) {
444
assert.ok(e instanceof TypeError)
445
assert.strictEqual('WebElementCondition did not resolve to a WebElement: ' + '[object Number]', e.message)
446
},
447
)
448
})
449
})
450
})
451
452