Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/common/driver.rb
1865 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
module Selenium
21
module WebDriver
22
#
23
# The main class through which you control the browser.
24
#
25
# @see SearchContext
26
# @see Navigation
27
# @see TargetLocator
28
# @see Options
29
#
30
31
class Driver
32
include SearchContext
33
include TakesScreenshot
34
35
class << self
36
#
37
# @api private
38
#
39
# @see Selenium::WebDriver.for
40
#
41
# @return [Driver]
42
#
43
44
def for(browser, opts = {})
45
case browser
46
when :chrome, :chrome_headless_shell
47
Chrome::Driver.new(**opts)
48
when :internet_explorer, :ie
49
IE::Driver.new(**opts)
50
when :safari
51
Safari::Driver.new(**opts)
52
when :firefox, :ff
53
Firefox::Driver.new(**opts)
54
when :edge, :microsoftedge, :msedge
55
Edge::Driver.new(**opts)
56
when :remote
57
Remote::Driver.new(**opts)
58
else
59
raise ArgumentError, "unknown driver: #{browser.inspect}"
60
end
61
end
62
end
63
64
#
65
# A new Driver instance with the given bridge.
66
# End users should use Selenium::WebDriver.for instead of using this directly.
67
#
68
# @api private
69
#
70
71
def initialize(bridge: nil, listener: nil, **)
72
@devtools = nil
73
bridge ||= create_bridge(**)
74
@bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
75
add_extensions(@bridge.browser)
76
end
77
78
def inspect
79
format '#<%<class>s:0x%<hash>x browser=%<browser>s>', class: self.class, hash: hash * 2,
80
browser: bridge.browser.inspect
81
end
82
83
#
84
# information about whether a remote end is in a state in which it can create new sessions,
85
# and may include additional meta information.
86
#
87
# @return [Hash]
88
#
89
def status
90
@bridge.status
91
end
92
93
#
94
# @return [Navigation]
95
# @see Navigation
96
#
97
98
def navigate
99
@navigate ||= WebDriver::Navigation.new(bridge)
100
end
101
102
#
103
# @return [Script]
104
# @see Script
105
#
106
107
def script
108
@script ||= WebDriver::Script.new(bridge)
109
end
110
111
#
112
# @return [TargetLocator]
113
# @see TargetLocator
114
#
115
116
def switch_to
117
@switch_to ||= WebDriver::TargetLocator.new(bridge)
118
end
119
120
#
121
# @return [Manager]
122
# @see Manager
123
#
124
125
def manage
126
bridge.manage
127
end
128
129
#
130
# @return [ActionBuilder]
131
# @see ActionBuilder
132
#
133
134
def action(**)
135
bridge.action(**)
136
end
137
138
#
139
# Opens the specified URL in the browser.
140
#
141
142
def get(url)
143
navigate.to(url)
144
end
145
146
#
147
# Get the URL of the current page
148
#
149
# @return [String]
150
#
151
152
def current_url
153
bridge.url
154
end
155
156
#
157
# Get the title of the current page
158
#
159
# @return [String]
160
#
161
162
def title
163
bridge.title
164
end
165
166
#
167
# Get the source of the current page
168
#
169
# @return [String]
170
#
171
172
def page_source
173
bridge.page_source
174
end
175
176
#
177
# Quit the browser
178
#
179
180
def quit
181
bridge.quit
182
ensure
183
@service_manager&.stop
184
@devtools&.each_value(&:close)
185
end
186
187
#
188
# Close the current window, or the browser if no windows are left.
189
#
190
191
def close
192
bridge&.close
193
end
194
195
#
196
# Get the window handles of open browser windows.
197
#
198
# @return [Array]
199
# @see TargetLocator#window
200
#
201
202
def window_handles
203
bridge.window_handles
204
end
205
206
#
207
# Get the current window handle
208
#
209
# @return [String]
210
#
211
212
def window_handle
213
bridge.window_handle
214
end
215
216
#
217
# Execute the given JavaScript
218
#
219
# @param [String] script
220
# JavaScript source to execute
221
# @param [WebDriver::Element, Integer, Float, Boolean, NilClass, String, Array] args
222
# Arguments will be available in the given script in the 'arguments' pseudo-array.
223
#
224
# @return [WebDriver::Element,Integer,Float,Boolean,NilClass,String,Array]
225
# The value returned from the script.
226
#
227
228
def execute_script(script, *)
229
bridge.execute_script(script, *)
230
end
231
232
# Execute an asynchronous piece of JavaScript in the context of the
233
# currently selected frame or window. Unlike executing
234
# execute_script (synchronous JavaScript), scripts
235
# executed with this method must explicitly signal they are finished by
236
# invoking the provided callback. This callback is always injected into the
237
# executed function as the last argument.
238
#
239
# @param [String] script
240
# JavaScript source to execute
241
# @param [WebDriver::Element,Integer, Float, Boolean, NilClass, String, Array] args
242
# Arguments to the script. May be empty.
243
#
244
# @return [WebDriver::Element,Integer,Float,Boolean,NilClass,String,Array]
245
#
246
247
def execute_async_script(script, *)
248
bridge.execute_async_script(script, *)
249
end
250
251
#
252
# @return [VirtualAuthenticator]
253
# @see VirtualAuthenticator
254
#
255
256
def add_virtual_authenticator(options)
257
bridge.add_virtual_authenticator(options)
258
end
259
260
#
261
# @return [Network]
262
# @see Network
263
#
264
265
def network
266
@network ||= WebDriver::Network.new(bridge)
267
end
268
269
#-------------------------------- sugar --------------------------------
270
271
#
272
# driver.first(id: 'foo')
273
#
274
275
alias first find_element
276
277
#
278
# driver.all(class: 'bar') #=> [#<WebDriver::Element:0x1011c3b88, ...]
279
#
280
281
alias all find_elements
282
283
# Get the first element matching the given selector. If given a
284
# String or Symbol, it will be used as the id of the element.
285
#
286
# @param [String,Hash] sel id or selector
287
# @return [WebDriver::Element]
288
#
289
# Examples:
290
#
291
# driver['someElementId'] #=> #<WebDriver::Element:0x1011c3b88>
292
# driver[:tag_name => 'div'] #=> #<WebDriver::Element:0x1011c3b88>
293
#
294
295
def [](sel)
296
sel = {id: sel} if sel.is_a?(String) || sel.is_a?(Symbol)
297
298
find_element sel
299
end
300
301
def browser
302
bridge.browser
303
end
304
305
def capabilities
306
bridge.capabilities
307
end
308
309
#
310
# @api private
311
# @see SearchContext
312
#
313
314
def ref
315
[:driver, nil]
316
end
317
318
private
319
320
attr_reader :bridge
321
322
def create_bridge(caps:, url:, http_client: nil)
323
klass = caps['webSocketUrl'] ? Remote::BiDiBridge : Remote::Bridge
324
klass.new(http_client: http_client, url: url).tap do |bridge|
325
bridge.create_session(caps)
326
end
327
end
328
329
def service_url(service)
330
@service_manager = service.launch
331
@service_manager.uri
332
end
333
334
def screenshot
335
bridge.screenshot
336
end
337
338
def add_extensions(browser)
339
extensions = case browser
340
when :chrome, :chrome_headless_shell, :msedge, :microsoftedge
341
Chromium::Driver::EXTENSIONS
342
when :firefox
343
Firefox::Driver::EXTENSIONS
344
when :safari, :safari_technology_preview
345
Safari::Driver::EXTENSIONS
346
when :ie, :internet_explorer
347
IE::Driver::EXTENSIONS
348
else
349
[]
350
end
351
extensions.each { |extension| extend extension }
352
end
353
end # Driver
354
end # WebDriver
355
end # Selenium
356
357