Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/selenium-webdriver/test/element_finding_test.js
2884 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
const promise = require('selenium-webdriver/lib/promise')
22
const { Browser, By, RelativeBy, error, withTagName, until } = require('selenium-webdriver')
23
const { Pages, ignore, suite, whereIs } = require('../lib/test')
24
const { locateWith } = require('selenium-webdriver/lib/by')
25
26
suite(function (env) {
27
const browsers = (...args) => env.browsers(...args)
28
29
let driver
30
31
before(async function () {
32
driver = await env.builder().build()
33
})
34
35
after(function () {
36
return driver.quit()
37
})
38
39
describe('finding elements', function () {
40
it('should work after loading multiple pages in a row', async function () {
41
await driver.get(Pages.formPage)
42
await driver.get(Pages.xhtmlTestPage)
43
await driver.findElement(By.linkText('click me')).click()
44
await driver.wait(until.titleIs('We Arrive Here'), 5000)
45
})
46
47
describe('By.id()', function () {
48
it('should work', async function () {
49
await driver.get(Pages.xhtmlTestPage)
50
await driver.findElement(By.id('linkId')).click()
51
await driver.wait(until.titleIs('We Arrive Here'), 5000)
52
})
53
54
it('should fail if ID not present on page', async function () {
55
await driver.get(Pages.formPage)
56
return driver.findElement(By.id('nonExistentButton')).then(assert.fail, function (e) {
57
assert.ok(e instanceof error.NoSuchElementError)
58
})
59
})
60
61
it('should find multiple elements by ID even though that is ' + 'malformed HTML', async function () {
62
await driver.get(Pages.nestedPage)
63
64
let elements = await driver.findElements(By.id('2'))
65
assert.strictEqual(elements.length, 8)
66
})
67
})
68
69
describe('By.linkText()', function () {
70
it('should be able to click on link identified by text', async function () {
71
await driver.get(Pages.xhtmlTestPage)
72
await driver.findElement(By.linkText('click me')).click()
73
await driver.wait(until.titleIs('We Arrive Here'), 5000)
74
})
75
76
it('should be able to find elements by partial link text', async function () {
77
await driver.get(Pages.xhtmlTestPage)
78
await driver.findElement(By.partialLinkText('ick me')).click()
79
await driver.wait(until.titleIs('We Arrive Here'), 5000)
80
})
81
82
it('should work when link text contains equals sign', async function () {
83
await driver.get(Pages.xhtmlTestPage)
84
let el = await driver.findElement(By.linkText('Link=equalssign'))
85
86
let id = await el.getAttribute('id')
87
assert.strictEqual(id, 'linkWithEqualsSign')
88
})
89
90
it('matches by partial text when containing equals sign', async function () {
91
await driver.get(Pages.xhtmlTestPage)
92
let link = await driver.findElement(By.partialLinkText('Link='))
93
94
let id = await link.getAttribute('id')
95
assert.strictEqual(id, 'linkWithEqualsSign')
96
})
97
98
it('works when searching for multiple and text contains =', async function () {
99
await driver.get(Pages.xhtmlTestPage)
100
let elements = await driver.findElements(By.linkText('Link=equalssign'))
101
102
assert.strictEqual(elements.length, 1)
103
104
let id = await elements[0].getAttribute('id')
105
assert.strictEqual(id, 'linkWithEqualsSign')
106
})
107
108
it('works when searching for multiple with partial text containing =', async function () {
109
await driver.get(Pages.xhtmlTestPage)
110
let elements = await driver.findElements(By.partialLinkText('Link='))
111
112
assert.strictEqual(elements.length, 1)
113
114
let id = await elements[0].getAttribute('id')
115
assert.strictEqual(id, 'linkWithEqualsSign')
116
})
117
118
it('should be able to find multiple exact matches', async function () {
119
await driver.get(Pages.xhtmlTestPage)
120
let elements = await driver.findElements(By.linkText('click me'))
121
assert.strictEqual(elements.length, 2)
122
})
123
124
it('should be able to find multiple partial matches', async function () {
125
await driver.get(Pages.xhtmlTestPage)
126
let elements = await driver.findElements(By.partialLinkText('ick me'))
127
assert.strictEqual(elements.length, 2)
128
})
129
130
ignore(browsers(Browser.SAFARI)).it('works on XHTML pages', async function () {
131
await driver.get(whereIs('actualXhtmlPage.xhtml'))
132
133
let el = await driver.findElement(By.linkText('Foo'))
134
assert.strictEqual(await el.getText(), 'Foo')
135
})
136
})
137
138
describe('By.name()', function () {
139
it('should work', async function () {
140
await driver.get(Pages.formPage)
141
142
let el = await driver.findElement(By.name('checky'))
143
assert.strictEqual(await el.getAttribute('value'), 'furrfu')
144
})
145
146
it('should find multiple elements with same name', async function () {
147
await driver.get(Pages.nestedPage)
148
149
let elements = await driver.findElements(By.name('checky'))
150
assert.ok(elements.length > 1)
151
})
152
153
it('should be able to find elements that do not support name property', async function () {
154
await driver.get(Pages.nestedPage)
155
await driver.findElement(By.name('div1'))
156
// Pass if this does not return an error.
157
})
158
159
it('should be able to find hidden elements by name', async function () {
160
await driver.get(Pages.formPage)
161
await driver.findElement(By.name('hidden'))
162
// Pass if this does not return an error.
163
})
164
})
165
166
describe('By.className()', function () {
167
it('should work', async function () {
168
await driver.get(Pages.xhtmlTestPage)
169
170
let el = await driver.findElement(By.className('extraDiv'))
171
let text = await el.getText()
172
assert.ok(text.startsWith('Another div starts here.'), `Unexpected text: "${text}"`)
173
})
174
175
it('should work when name is first name among many', async function () {
176
await driver.get(Pages.xhtmlTestPage)
177
178
let el = await driver.findElement(By.className('nameA'))
179
assert.strictEqual(await el.getText(), 'An H2 title')
180
})
181
182
it('should work when name is last name among many', async function () {
183
await driver.get(Pages.xhtmlTestPage)
184
185
let el = await driver.findElement(By.className('nameC'))
186
assert.strictEqual(await el.getText(), 'An H2 title')
187
})
188
189
it('should work when name is middle of many', async function () {
190
await driver.get(Pages.xhtmlTestPage)
191
192
let el = await driver.findElement(By.className('nameBnoise'))
193
assert.strictEqual(await el.getText(), 'An H2 title')
194
})
195
196
it('should work when name surrounded by whitespace', async function () {
197
await driver.get(Pages.xhtmlTestPage)
198
199
let el = await driver.findElement(By.className('spaceAround'))
200
assert.strictEqual(await el.getText(), 'Spaced out')
201
})
202
203
it('should fail if queried name only partially matches', async function () {
204
await driver.get(Pages.xhtmlTestPage)
205
return driver.findElement(By.className('nameB')).then(assert.fail, function (e) {
206
assert.ok(e instanceof error.NoSuchElementError)
207
})
208
})
209
210
it('should implicitly wait', async function () {
211
const TIMEOUT_IN_MS = 1000
212
const EPSILON = TIMEOUT_IN_MS / 2
213
214
await driver.manage().setTimeouts({ implicit: TIMEOUT_IN_MS })
215
await driver.get(Pages.formPage)
216
217
let start = new Date()
218
return driver.findElement(By.id('nonExistentButton')).then(assert.fail, function (e) {
219
let end = new Date()
220
assert.ok(e instanceof error.NoSuchElementError)
221
222
let elapsed = end - start
223
let diff = Math.abs(elapsed - TIMEOUT_IN_MS)
224
assert.ok(diff < EPSILON, `Expected ${TIMEOUT_IN_MS} \u00b1 ${EPSILON} but got ${elapsed}`)
225
})
226
})
227
228
it('should be able to find multiple matches', async function () {
229
await driver.get(Pages.xhtmlTestPage)
230
231
let elements = await driver.findElements(By.className('nameC'))
232
assert.ok(elements.length > 1)
233
})
234
235
it('permits compound class names', function () {
236
return driver
237
.get(Pages.xhtmlTestPage)
238
.then(() => driver.findElement(By.className('nameA nameC')))
239
.then((el) => el.getText())
240
.then((text) => assert.strictEqual(text, 'An H2 title'))
241
})
242
})
243
244
describe('By.xpath()', function () {
245
it('should work with multiple matches', async function () {
246
await driver.get(Pages.xhtmlTestPage)
247
let elements = await driver.findElements(By.xpath('//div'))
248
assert.ok(elements.length > 1)
249
})
250
251
it('should work for selectors using contains keyword', async function () {
252
await driver.get(Pages.nestedPage)
253
await driver.findElement(By.xpath('//a[contains(., "hello world")]'))
254
// Pass if no error.
255
})
256
})
257
258
describe('By.tagName()', function () {
259
it('works', async function () {
260
await driver.get(Pages.formPage)
261
262
let el = await driver.findElement(By.tagName('input'))
263
assert.strictEqual((await el.getTagName()).toLowerCase(), 'input')
264
})
265
266
it('can find multiple elements', async function () {
267
await driver.get(Pages.formPage)
268
269
let elements = await driver.findElements(By.tagName('input'))
270
assert.ok(elements.length > 1)
271
})
272
})
273
274
describe('By.css()', function () {
275
it('works', async function () {
276
await driver.get(Pages.xhtmlTestPage)
277
await driver.findElement(By.css('div.content'))
278
// Pass if no error.
279
})
280
281
it('can find multiple elements', async function () {
282
await driver.get(Pages.xhtmlTestPage)
283
284
let elements = await driver.findElements(By.css('p'))
285
assert.ok(elements.length > 1)
286
// Pass if no error.
287
})
288
289
it('should find first matching element when searching by ' + 'compound CSS selector', async function () {
290
await driver.get(Pages.xhtmlTestPage)
291
292
let el = await driver.findElement(By.css('div.extraDiv, div.content'))
293
assert.strictEqual(await el.getAttribute('class'), 'content')
294
})
295
296
it('should be able to find multiple elements by compound selector', async function () {
297
await driver.get(Pages.xhtmlTestPage)
298
let elements = await driver.findElements(By.css('div.extraDiv, div.content'))
299
300
return Promise.all([assertClassIs(elements[0], 'content'), assertClassIs(elements[1], 'extraDiv')])
301
302
async function assertClassIs(el, expected) {
303
let clazz = await el.getAttribute('class')
304
assert.strictEqual(clazz, expected)
305
}
306
})
307
308
// IE only supports short version option[selected].
309
ignore(browsers(Browser.INTERNET_EXPLORER)).it(
310
'should be able to find element by boolean attribute',
311
async function () {
312
await driver.get(whereIs('locators_tests/boolean_attribute_selected.html'))
313
314
let el = await driver.findElement(By.css('option[selected="selected"]'))
315
assert.strictEqual(await el.getAttribute('value'), 'two')
316
},
317
)
318
319
it('should be able to find element with short ' + 'boolean attribute selector', async function () {
320
await driver.get(whereIs('locators_tests/boolean_attribute_selected.html'))
321
322
let el = await driver.findElement(By.css('option[selected]'))
323
assert.strictEqual(await el.getAttribute('value'), 'two')
324
})
325
326
it('should be able to find element with short boolean attribute ' + 'selector on HTML4 page', async function () {
327
await driver.get(whereIs('locators_tests/boolean_attribute_selected_html4.html'))
328
329
let el = await driver.findElement(By.css('option[selected]'))
330
assert.strictEqual(await el.getAttribute('value'), 'two')
331
})
332
})
333
334
describe('by custom locator', function () {
335
it('handles single element result', async function () {
336
await driver.get(Pages.javascriptPage)
337
338
let link = await driver.findElement(function (driver) {
339
let links = driver.findElements(By.tagName('a'))
340
return promise
341
.filter(links, function (link) {
342
return link.getAttribute('id').then((id) => id === 'updatediv')
343
})
344
.then((links) => links[0])
345
})
346
347
let text = await link.getText()
348
let regex = /Update\s+a\s+div/
349
assert.ok(regex.test(text), `"${text}" does not match ${regex}`)
350
})
351
352
it('uses first element if locator resolves to list', async function () {
353
await driver.get(Pages.javascriptPage)
354
355
let link = await driver.findElement(function () {
356
return driver.findElements(By.tagName('a'))
357
})
358
359
assert.strictEqual(await link.getText(), 'Change the page title!')
360
})
361
362
it('fails if locator returns non-webelement value', async function () {
363
await driver.get(Pages.javascriptPage)
364
365
let link = driver.findElement(function () {
366
return driver.getTitle()
367
})
368
369
return link.then(
370
() => assert.fail('Should have failed'),
371
(e) => assert.ok(e instanceof TypeError),
372
)
373
})
374
})
375
376
describe('RelativeBy to find element', function () {
377
it('finds an element above', async function () {
378
await driver.get(Pages.relativeLocators)
379
let below = await driver.findElement(By.id('below'))
380
let elements = await driver.findElements(withTagName('p').above(below))
381
let ids = []
382
assert.strictEqual(elements.length, 2)
383
for (let i = 0; i < elements.length; i++) {
384
ids.push(await elements[i].getAttribute('id'))
385
}
386
assert.deepStrictEqual(ids, ['mid', 'above'])
387
})
388
389
it('should combine filters', async function () {
390
await driver.get(Pages.relativeLocators)
391
392
let elements = await driver.findElements(withTagName('td').above(By.id('center')).toRightOf(By.id('top')))
393
let ids = []
394
for (let i = 0; i < elements.length; i++) {
395
ids.push(await elements[i].getAttribute('id'))
396
}
397
assert.notDeepStrictEqual(ids.indexOf('topRight'), -1, `Elements are ${ids}`)
398
})
399
})
400
401
describe('RelativeBy with findElement', function () {
402
it('finds an element above', async function () {
403
await driver.get(Pages.relativeLocators)
404
let below = await driver.findElement(By.id('below'))
405
let element = await driver.findElement(withTagName('p').above(below))
406
assert.deepStrictEqual(await element.getAttribute('id'), `mid`)
407
})
408
409
it('should combine filters', async function () {
410
await driver.get(Pages.relativeLocators)
411
let element = await driver.findElement(withTagName('td').above(By.id('center')).toRightOf(By.id('top')))
412
assert.deepStrictEqual(await element.getAttribute('id'), `topRight`)
413
})
414
415
it('should search by passing in a by object', async function () {
416
await driver.get(Pages.relativeLocators)
417
let relativeLocator = locateWith(By.css('p')).above(await driver.findElement(By.id('below')))
418
assert.ok(relativeLocator instanceof RelativeBy)
419
420
let element = await driver.findElement(relativeLocator)
421
assert.deepStrictEqual(await element.getAttribute('id'), 'mid')
422
})
423
})
424
425
describe('switchTo().activeElement()', function () {
426
// SAFARI's new session response does not identify it as a W3C browser,
427
// so the command is sent in the unsupported wire protocol format.
428
ignore(browsers(Browser.SAFARI)).it('returns document.activeElement', async function () {
429
await driver.get(Pages.formPage)
430
431
let email = await driver.findElement(By.css('#email'))
432
await driver.executeScript('arguments[0].focus()', email)
433
434
let ae = await driver.switchTo().activeElement()
435
let equal = await driver.executeScript('return arguments[0] === arguments[1]', email, ae)
436
assert.ok(equal)
437
})
438
})
439
})
440
})
441
442