Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/spec/integration/selenium/webdriver/driver_spec.rb
1864 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
require_relative 'spec_helper'
21
22
module Selenium
23
module WebDriver
24
describe Driver, exclusive: {bidi: false, reason: 'Not yet implemented with BiDi'} do
25
after { reset_driver! if GlobalTestEnv.rbe? && GlobalTestEnv.browser == :chrome }
26
27
it_behaves_like 'driver that can be started concurrently', exclude: [
28
{browser: %i[safari safari_preview]},
29
{browser: :firefox, reason: 'https://github.com/SeleniumHQ/selenium/issues/15451'},
30
{driver: :remote, rbe: true, reason: 'Cannot start 2+ drivers at once.'}
31
]
32
33
it 'creates default capabilities', exclude: {browser: %i[safari safari_preview]} do
34
reset_driver! do |driver|
35
caps = driver.capabilities
36
expect(caps.proxy).to be_nil
37
expect(caps.browser_version).to match(/^\d\d\d?\./)
38
expect(caps.platform_name).not_to be_nil
39
40
expect(caps.accept_insecure_certs).to eq(caps.browser_name == 'firefox')
41
expect(caps.page_load_strategy).to eq 'normal'
42
expect(caps.implicit_timeout).to be_zero
43
expect(caps.page_load_timeout).to eq 300000
44
expect(caps.script_timeout).to eq 30000
45
end
46
end
47
48
it 'gets driver status' do
49
status = driver.status
50
expect(status).to include('ready', 'message')
51
end
52
53
it 'gets the page title' do
54
driver.navigate.to url_for('xhtmlTest.html')
55
expect(driver.title).to eq('XHTML Test Page')
56
end
57
58
it 'gets the page source' do
59
driver.navigate.to url_for('xhtmlTest.html')
60
expect(driver.page_source).to match(%r{<title>XHTML Test Page</title>}i)
61
end
62
63
it 'refreshes the page' do
64
driver.navigate.to url_for('javascriptPage.html')
65
short_wait { driver.find_element(id: 'updatediv') }.click
66
expect(driver.find_element(id: 'dynamo').text).to eq('Fish and chips!')
67
driver.navigate.refresh
68
wait_for_element(id: 'dynamo')
69
expect(driver.find_element(id: 'dynamo').text).to eq("What's for dinner?")
70
end
71
72
describe 'one element' do
73
it 'finds by id' do
74
driver.navigate.to url_for('xhtmlTest.html')
75
element = driver.find_element(id: 'id1')
76
expect(element).to be_a(WebDriver::Element)
77
expect(element.text).to eq('Foo')
78
end
79
80
it 'finds by field name' do
81
driver.navigate.to url_for('formPage.html')
82
expect(driver.find_element(name: 'x').attribute('value')).to eq('name')
83
end
84
85
it 'finds by class name' do # rubocop:disable RSpec/RepeatedExample
86
driver.navigate.to url_for('xhtmlTest.html')
87
expect(driver.find_element(class: 'header').text).to eq('XHTML Might Be The Future')
88
end
89
90
# TODO: Rewrite this test so it's not a duplicate of above or remove
91
it 'finds elements with a hash selector' do # rubocop:disable RSpec/RepeatedExample
92
driver.navigate.to url_for('xhtmlTest.html')
93
expect(driver.find_element(class: 'header').text).to eq('XHTML Might Be The Future')
94
end
95
96
it 'finds by link text' do
97
driver.navigate.to url_for('xhtmlTest.html')
98
expect(driver.find_element(link: 'Foo').text).to eq('Foo')
99
end
100
101
it 'finds by xpath' do
102
driver.navigate.to url_for('xhtmlTest.html')
103
expect(driver.find_element(xpath: '//h1').text).to eq('XHTML Might Be The Future')
104
end
105
106
it 'finds by css selector' do
107
driver.navigate.to url_for('xhtmlTest.html')
108
expect(driver.find_element(css: 'div.content').attribute('class')).to eq('content')
109
end
110
111
it 'finds by tag name' do
112
driver.navigate.to url_for('xhtmlTest.html')
113
expect(driver.find_element(tag_name: 'div').attribute('class')).to eq('navigation')
114
end
115
116
it 'finds above another' do
117
driver.navigate.to url_for('relative_locators.html')
118
119
above = driver.find_element(relative: {tag_name: 'td', above: {id: 'center'}})
120
expect(above.attribute('id')).to eq('top')
121
end
122
123
it 'finds child element' do
124
driver.navigate.to url_for('nestedElements.html')
125
126
element = driver.find_element(name: 'form2')
127
child = element.find_element(name: 'selectomatic')
128
129
expect(child.attribute('id')).to eq('2')
130
end
131
132
it 'finds child element by tag name' do
133
driver.navigate.to url_for('nestedElements.html')
134
135
element = driver.find_element(name: 'form2')
136
child = element.find_element(tag_name: 'select')
137
138
expect(child.attribute('id')).to eq('2')
139
end
140
141
it 'finds elements with the shortcut syntax' do
142
driver.navigate.to url_for('xhtmlTest.html')
143
144
expect(driver[:id1]).to be_a(WebDriver::Element)
145
expect(driver[xpath: '//h1']).to be_a(WebDriver::Element)
146
end
147
148
it 'raises if element not found' do
149
driver.navigate.to url_for('xhtmlTest.html')
150
expect {
151
driver.find_element(id: 'not-there')
152
}.to raise_error(Error::NoSuchElementError, /errors#no-such-element-exception/)
153
end
154
155
it 'raises if invalid locator',
156
exclude: {browser: %i[safari safari_preview], reason: 'Safari TimeoutError'} do
157
driver.navigate.to url_for('xhtmlTest.html')
158
expect {
159
driver.find_element(xpath: '*?//-')
160
}.to raise_error(Error::InvalidSelectorError, /errors#invalid-selector-exception/)
161
end
162
end
163
164
describe 'many elements' do
165
it 'finds by class name' do
166
driver.navigate.to url_for('xhtmlTest.html')
167
expect(driver.find_elements(class: 'nameC').size).to eq(2)
168
end
169
170
it 'finds by css selector' do
171
driver.navigate.to url_for('xhtmlTest.html')
172
expect(driver.find_elements(css: 'p').size).to be_positive
173
end
174
175
it 'finds above element' do
176
driver.navigate.to url_for('relative_locators.html')
177
178
lowest = driver.find_element(id: 'below')
179
above = driver.find_elements(relative: {tag_name: 'p', above: lowest})
180
expect(above.map { |e| e.attribute('id') }).to eq(%w[mid above])
181
end
182
183
it 'finds above another' do
184
driver.navigate.to url_for('relative_locators.html')
185
186
above = driver.find_elements(relative: {css: 'td', above: {id: 'center'}})
187
expect(above.map { |e| e.attribute('id') }).to eq(%w[top topLeft topRight])
188
end
189
190
it 'finds below element' do
191
driver.navigate.to url_for('relative_locators.html')
192
193
midpoint = driver.find_element(id: 'mid')
194
above = driver.find_elements(relative: {id: 'below', below: midpoint})
195
expect(above.map { |e| e.attribute('id') }).to eq(['below'])
196
end
197
198
it 'finds near another within default distance' do
199
driver.navigate.to url_for('relative_locators.html')
200
201
near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'right'}})
202
expect(near.map { |e| e.attribute('id') }).to eq(%w[topRight bottomRight center top bottom])
203
end
204
205
it 'finds near another within custom distance', except: {browser: %i[safari safari_preview]} do
206
driver.navigate.to url_for('relative_locators.html')
207
208
near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'right', distance: 100}})
209
expect(near.map { |e| e.attribute('id') }).to eq(%w[topRight bottomRight center top bottom])
210
end
211
212
it 'finds to the left of another' do
213
driver.navigate.to url_for('relative_locators.html')
214
215
left = driver.find_elements(relative: {tag_name: 'td', left: {id: 'center'}})
216
expect(left.map { |e| e.attribute('id') }).to eq(%w[left topLeft bottomLeft])
217
end
218
219
it 'finds to the right of another' do
220
driver.navigate.to url_for('relative_locators.html')
221
222
right = driver.find_elements(relative: {tag_name: 'td', right: {id: 'center'}})
223
expect(right.map { |e| e.attribute('id') }).to eq(%w[right topRight bottomRight])
224
end
225
226
it 'finds by combined relative locators' do
227
driver.navigate.to url_for('relative_locators.html')
228
229
found = driver.find_elements(relative: {tag_name: 'td', right: {id: 'top'}, above: {id: 'center'}})
230
expect(found.map { |e| e.attribute('id') }).to eq(['topRight'])
231
end
232
233
it 'finds all by empty relative locator' do
234
driver.navigate.to url_for('relative_locators.html')
235
236
expected = driver.find_elements(tag_name: 'p')
237
actual = driver.find_elements(relative: {tag_name: 'p'})
238
expect(actual).to eq(expected)
239
end
240
241
it 'finds children by field name' do
242
driver.navigate.to url_for('nestedElements.html')
243
element = driver.find_element(name: 'form2')
244
children = element.find_elements(name: 'selectomatic')
245
expect(children.size).to eq(2)
246
end
247
end
248
249
describe '#execute_script' do
250
it 'returns strings' do
251
driver.navigate.to url_for('xhtmlTest.html')
252
expect(driver.execute_script('return document.title;')).to eq('XHTML Test Page')
253
end
254
255
it 'returns numbers' do
256
driver.navigate.to url_for('xhtmlTest.html')
257
expect(driver.execute_script('return document.title.length;')).to eq(15)
258
end
259
260
it 'returns elements' do
261
driver.navigate.to url_for('xhtmlTest.html')
262
element = driver.execute_script("return document.getElementById('id1');")
263
expect(element).to be_a(WebDriver::Element)
264
expect(element.text).to eq('Foo')
265
end
266
267
it 'unwraps elements in deep objects' do
268
driver.navigate.to url_for('xhtmlTest.html')
269
result = driver.execute_script(<<~SCRIPT)
270
var e1 = document.getElementById('id1');
271
var body = document.body;
272
273
return {
274
elements: {'body' : body, other: [e1] }
275
};
276
SCRIPT
277
278
expect(result).to be_a(Hash)
279
expect(result['elements']['body']).to be_a(WebDriver::Element)
280
expect(result['elements']['other'].first).to be_a(WebDriver::Element)
281
end
282
283
it 'returns booleans' do
284
driver.navigate.to url_for('xhtmlTest.html')
285
expect(driver.execute_script('return true;')).to be(true)
286
end
287
288
it 'raises if the script is bad' do
289
driver.navigate.to url_for('xhtmlTest.html')
290
expect {
291
driver.execute_script('return squiggle();')
292
}.to raise_error(Selenium::WebDriver::Error::JavascriptError)
293
end
294
295
it 'returns arrays' do
296
driver.navigate.to url_for('xhtmlTest.html')
297
expect(driver.execute_script('return ["zero", "one", "two"];')).to eq(%w[zero one two])
298
end
299
300
it 'is able to call functions on the page' do
301
driver.navigate.to url_for('javascriptPage.html')
302
driver.execute_script("displayMessage('I like cheese');")
303
expect(driver.find_element(id: 'result').text.strip).to eq('I like cheese')
304
end
305
306
it 'is able to pass string arguments' do
307
driver.navigate.to url_for('javascriptPage.html')
308
expect(driver.execute_script("return arguments[0] == 'fish' ? 'fish' : 'not fish';", 'fish')).to eq('fish')
309
end
310
311
it 'is able to pass boolean arguments' do
312
driver.navigate.to url_for('javascriptPage.html')
313
expect(driver.execute_script('return arguments[0] == true;', true)).to be(true)
314
end
315
316
it 'is able to pass numeric arguments' do
317
driver.navigate.to url_for('javascriptPage.html')
318
expect(driver.execute_script('return arguments[0] == 1 ? 1 : 0;', 1)).to eq(1)
319
end
320
321
it 'is able to pass null arguments' do
322
driver.navigate.to url_for('javascriptPage.html')
323
expect(driver.execute_script('return arguments[0];', nil)).to be_nil
324
end
325
326
it 'is able to pass array arguments' do
327
driver.navigate.to url_for('javascriptPage.html')
328
expect(driver.execute_script('return arguments[0];', [1, '2', 3])).to eq([1, '2', 3])
329
end
330
331
it 'is able to pass element arguments' do
332
driver.navigate.to url_for('javascriptPage.html')
333
button = driver.find_element(id: 'plainButton')
334
js = "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble'];"
335
expect(driver.execute_script(js, button))
336
.to eq('plainButton')
337
end
338
339
it 'is able to pass in multiple arguments' do
340
driver.navigate.to url_for('javascriptPage.html')
341
expect(driver.execute_script('return arguments[0] + arguments[1];', 'one', 'two')).to eq('onetwo')
342
end
343
end
344
345
describe 'execute async script' do
346
before do
347
driver.manage.timeouts.script = 1
348
driver.navigate.to url_for('ajaxy_page.html')
349
end
350
351
it 'is able to return arrays of primitives from async scripts' do
352
result = driver.execute_async_script "arguments[arguments.length - 1]([null, 123, 'abc', true, false]);"
353
expect(result).to eq([nil, 123, 'abc', true, false])
354
end
355
356
it 'is able to pass multiple arguments to async scripts' do
357
result = driver.execute_async_script 'arguments[arguments.length - 1](arguments[0] + arguments[1]);', 1, 2
358
expect(result).to eq(3)
359
end
360
361
# Safari raises TimeoutError instead
362
it 'times out if the callback is not invoked', except: {browser: %i[safari safari_preview]} do
363
expect {
364
# Script is expected to be async and explicitly callback, so this should timeout.
365
driver.execute_async_script 'return 1 + 2;'
366
}.to raise_error(Selenium::WebDriver::Error::ScriptTimeoutError)
367
end
368
end
369
end
370
end # WebDriver
371
end # Selenium
372
373