selenium-webdriver 4.0.0.alpha2 → 4.0.0
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.
- checksums.yaml +5 -5
- data/CHANGES +338 -4
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/NOTICE +2 -0
- data/README.md +4 -5
- data/lib/selenium/server.rb +21 -29
- data/lib/selenium/webdriver/atoms/findElements.js +122 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
- data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
- data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
- data/lib/selenium/webdriver/chrome/driver.rb +26 -56
- data/lib/selenium/webdriver/chrome/features.rb +106 -0
- data/lib/selenium/webdriver/chrome/options.rb +127 -52
- data/lib/selenium/webdriver/chrome/profile.rb +8 -5
- data/lib/selenium/webdriver/chrome/service.rb +4 -6
- data/lib/selenium/webdriver/chrome.rb +10 -9
- data/lib/selenium/webdriver/common/driver.rb +110 -19
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +43 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
- data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
- data/lib/selenium/webdriver/common/element.rb +79 -16
- data/lib/selenium/webdriver/common/error.rb +12 -0
- data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
- data/lib/selenium/webdriver/common/log_entry.rb +2 -2
- data/lib/selenium/webdriver/common/logger.rb +50 -15
- data/lib/selenium/webdriver/common/manager.rb +14 -14
- data/lib/selenium/webdriver/common/options.rb +186 -0
- data/lib/selenium/webdriver/common/platform.rb +6 -1
- data/lib/selenium/webdriver/common/port_prober.rb +4 -6
- data/lib/selenium/webdriver/common/profile_helper.rb +10 -2
- data/lib/selenium/webdriver/common/proxy.rb +6 -3
- data/lib/selenium/webdriver/common/search_context.rb +7 -3
- data/lib/selenium/webdriver/common/service.rb +23 -113
- data/lib/selenium/webdriver/common/service_manager.rb +151 -0
- data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
- data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
- data/lib/selenium/webdriver/common/target_locator.rb +32 -4
- data/lib/selenium/webdriver/common/timeouts.rb +31 -4
- data/lib/selenium/webdriver/common/wait.rb +1 -1
- data/lib/selenium/webdriver/common/window.rb +0 -4
- data/lib/selenium/webdriver/common.rb +17 -2
- data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
- data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
- data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
- data/lib/selenium/webdriver/{chrome/bridge.rb → devtools/pinned_script.rb} +26 -17
- data/lib/selenium/webdriver/devtools/request.rb +67 -0
- data/lib/selenium/webdriver/devtools/response.rb +66 -0
- data/lib/selenium/webdriver/devtools.rb +182 -0
- data/lib/selenium/webdriver/edge/driver.rb +5 -31
- data/lib/selenium/webdriver/edge/features.rb +44 -0
- data/lib/selenium/webdriver/edge/options.rb +11 -48
- data/lib/selenium/webdriver/edge/profile.rb +33 -0
- data/lib/selenium/webdriver/edge/service.rb +9 -24
- data/lib/selenium/webdriver/edge.rb +11 -13
- data/lib/selenium/webdriver/firefox/driver.rb +20 -30
- data/lib/selenium/webdriver/firefox/extension.rb +8 -0
- data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +23 -4
- data/lib/selenium/webdriver/firefox/options.rb +70 -49
- data/lib/selenium/webdriver/firefox/profile.rb +16 -77
- data/lib/selenium/webdriver/firefox/service.rb +1 -5
- data/lib/selenium/webdriver/firefox.rb +22 -16
- data/lib/selenium/webdriver/ie/driver.rb +1 -34
- data/lib/selenium/webdriver/ie/options.rb +13 -44
- data/lib/selenium/webdriver/ie/service.rb +9 -11
- data/lib/selenium/webdriver/ie.rb +8 -7
- data/lib/selenium/webdriver/remote/bridge.rb +112 -86
- data/lib/selenium/webdriver/remote/capabilities.rb +120 -62
- data/lib/selenium/webdriver/remote/commands.rb +7 -0
- data/lib/selenium/webdriver/remote/driver.rb +15 -12
- data/lib/selenium/webdriver/remote/http/common.rb +0 -5
- data/lib/selenium/webdriver/remote/http/default.rb +17 -11
- data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
- data/lib/selenium/webdriver/remote.rb +15 -9
- data/lib/selenium/webdriver/safari/driver.rb +3 -34
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +6 -6
- data/lib/selenium/webdriver/safari/options.rb +10 -29
- data/lib/selenium/webdriver/safari/service.rb +0 -4
- data/lib/selenium/webdriver/safari.rb +16 -8
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
- data/lib/selenium/webdriver/support/color.rb +2 -2
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
- data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
- data/lib/selenium/webdriver/support/guards.rb +95 -0
- data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
- data/lib/selenium/webdriver/support/select.rb +2 -2
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +10 -8
- data/selenium-webdriver.gemspec +29 -13
- metadata +125 -51
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
- data/lib/selenium/webdriver/firefox/binary.rb +0 -110
- data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
|
@@ -39,23 +39,17 @@ module Selenium
|
|
|
39
39
|
:timeouts,
|
|
40
40
|
:unhandled_prompt_behavior,
|
|
41
41
|
:strict_file_interactability,
|
|
42
|
+
:web_socket_url,
|
|
42
43
|
|
|
43
|
-
# remote-specific
|
|
44
|
-
:remote_session_id
|
|
45
|
-
|
|
46
|
-
# TODO: (AR) deprecate compatibility with OSS-capabilities
|
|
47
|
-
:implicit_timeout,
|
|
48
|
-
:page_load_timeout,
|
|
49
|
-
:script_timeout
|
|
44
|
+
# remote-specific (webdriver.remote.sessionid)
|
|
45
|
+
:remote_session_id
|
|
50
46
|
].freeze
|
|
51
47
|
|
|
52
|
-
KNOWN.each do |key|
|
|
48
|
+
(KNOWN - %i[proxy timeouts]).each do |key|
|
|
53
49
|
define_method key do
|
|
54
|
-
@capabilities
|
|
50
|
+
@capabilities[key]
|
|
55
51
|
end
|
|
56
52
|
|
|
57
|
-
next if key == :proxy
|
|
58
|
-
|
|
59
53
|
define_method "#{key}=" do |value|
|
|
60
54
|
@capabilities[key] = value
|
|
61
55
|
end
|
|
@@ -83,27 +77,21 @@ module Selenium
|
|
|
83
77
|
|
|
84
78
|
def edge(opts = {})
|
|
85
79
|
new({
|
|
86
|
-
browser_name: 'MicrosoftEdge'
|
|
87
|
-
platform_name: :windows
|
|
80
|
+
browser_name: 'MicrosoftEdge'
|
|
88
81
|
}.merge(opts))
|
|
89
82
|
end
|
|
83
|
+
alias_method :microsoftedge, :edge
|
|
90
84
|
|
|
91
85
|
def firefox(opts = {})
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
opts
|
|
95
|
-
opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
|
|
96
|
-
opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
|
|
97
|
-
opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
|
|
98
|
-
new({browser_name: 'firefox'}.merge(opts))
|
|
86
|
+
new({
|
|
87
|
+
browser_name: 'firefox'
|
|
88
|
+
}.merge(opts))
|
|
99
89
|
end
|
|
100
|
-
|
|
101
90
|
alias_method :ff, :firefox
|
|
102
91
|
|
|
103
92
|
def safari(opts = {})
|
|
104
93
|
new({
|
|
105
|
-
browser_name: 'safari'
|
|
106
|
-
platform_name: :mac
|
|
94
|
+
browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
|
|
107
95
|
}.merge(opts))
|
|
108
96
|
end
|
|
109
97
|
|
|
@@ -121,26 +109,23 @@ module Selenium
|
|
|
121
109
|
end
|
|
122
110
|
alias_method :ie, :internet_explorer
|
|
123
111
|
|
|
112
|
+
def always_match(capabilities)
|
|
113
|
+
new(always_match: capabilities)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def first_match(*capabilities)
|
|
117
|
+
new(first_match: capabilities)
|
|
118
|
+
end
|
|
119
|
+
|
|
124
120
|
#
|
|
125
121
|
# @api private
|
|
126
122
|
#
|
|
127
123
|
|
|
128
124
|
def json_create(data)
|
|
129
125
|
data = data.dup
|
|
130
|
-
|
|
131
126
|
caps = new
|
|
132
|
-
|
|
133
|
-
caps
|
|
134
|
-
caps.platform_name = data.delete('platformName') if data.key?('platformName')
|
|
135
|
-
caps.accept_insecure_certs = data.delete('acceptInsecureCerts') if data.key?('acceptInsecureCerts')
|
|
136
|
-
caps.page_load_strategy = data.delete('pageLoadStrategy') if data.key?('pageLoadStrategy')
|
|
137
|
-
|
|
138
|
-
if data.key?('timeouts')
|
|
139
|
-
timeouts = data.delete('timeouts')
|
|
140
|
-
caps.implicit_timeout = timeouts['implicit'] if timeouts
|
|
141
|
-
caps.page_load_timeout = timeouts['pageLoad'] if timeouts
|
|
142
|
-
caps.script_timeout = timeouts['script'] if timeouts
|
|
143
|
-
end
|
|
127
|
+
|
|
128
|
+
process_timeouts(caps, data.delete('timeouts'))
|
|
144
129
|
|
|
145
130
|
if data.key?('proxy')
|
|
146
131
|
proxy = data.delete('proxy')
|
|
@@ -148,13 +133,34 @@ module Selenium
|
|
|
148
133
|
end
|
|
149
134
|
|
|
150
135
|
# Remote Server Specific
|
|
151
|
-
|
|
136
|
+
if data.key?('webdriver.remote.sessionid')
|
|
137
|
+
caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
KNOWN.each do |cap|
|
|
141
|
+
data_value = camel_case(cap)
|
|
142
|
+
caps[cap] = data.delete(data_value) if data.key?(data_value)
|
|
143
|
+
end
|
|
152
144
|
|
|
153
145
|
# any remaining pairs will be added as is, with no conversion
|
|
154
146
|
caps.merge!(data)
|
|
155
147
|
|
|
156
148
|
caps
|
|
157
149
|
end
|
|
150
|
+
|
|
151
|
+
def camel_case(str_or_sym)
|
|
152
|
+
str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
|
|
157
|
+
def process_timeouts(caps, timeouts)
|
|
158
|
+
return if timeouts.nil?
|
|
159
|
+
|
|
160
|
+
caps.implicit_timeout = timeouts['implicit']
|
|
161
|
+
caps.page_load_timeout = timeouts['pageLoad']
|
|
162
|
+
caps.script_timeout = timeouts['script']
|
|
163
|
+
end
|
|
158
164
|
end
|
|
159
165
|
|
|
160
166
|
#
|
|
@@ -169,8 +175,9 @@ module Selenium
|
|
|
169
175
|
#
|
|
170
176
|
|
|
171
177
|
def initialize(opts = {})
|
|
172
|
-
@capabilities =
|
|
173
|
-
self.proxy = opts.delete(:proxy)
|
|
178
|
+
@capabilities = {}
|
|
179
|
+
self.proxy = opts.delete(:proxy) if opts[:proxy]
|
|
180
|
+
@capabilities.merge!(opts)
|
|
174
181
|
end
|
|
175
182
|
|
|
176
183
|
#
|
|
@@ -195,6 +202,10 @@ module Selenium
|
|
|
195
202
|
end
|
|
196
203
|
end
|
|
197
204
|
|
|
205
|
+
def proxy
|
|
206
|
+
@capabilities[:proxy]
|
|
207
|
+
end
|
|
208
|
+
|
|
198
209
|
def proxy=(proxy)
|
|
199
210
|
case proxy
|
|
200
211
|
when Hash
|
|
@@ -206,33 +217,46 @@ module Selenium
|
|
|
206
217
|
end
|
|
207
218
|
end
|
|
208
219
|
|
|
220
|
+
def timeouts
|
|
221
|
+
@capabilities[:timeouts] ||= {}
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def timeouts=(timeouts)
|
|
225
|
+
@capabilities[:timeouts] = timeouts
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def implicit_timeout
|
|
229
|
+
timeouts[:implicit]
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def implicit_timeout=(timeout)
|
|
233
|
+
timeouts[:implicit] = timeout
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def page_load_timeout
|
|
237
|
+
timeouts[:page_load] || timeouts[:pageLoad]
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def page_load_timeout=(timeout)
|
|
241
|
+
timeouts[:page_load] = timeout
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def script_timeout
|
|
245
|
+
timeouts[:script]
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def script_timeout=(timeout)
|
|
249
|
+
timeouts[:script] = timeout
|
|
250
|
+
end
|
|
251
|
+
|
|
209
252
|
#
|
|
210
253
|
# @api private
|
|
211
254
|
#
|
|
212
255
|
|
|
213
256
|
def as_json(*)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
@capabilities.each do |key, value|
|
|
217
|
-
case key
|
|
218
|
-
when :platform
|
|
219
|
-
hash['platform'] = value.to_s.upcase
|
|
220
|
-
when :proxy
|
|
221
|
-
if value
|
|
222
|
-
hash['proxy'] = value.as_json
|
|
223
|
-
hash['proxy']['proxyType'] &&= hash['proxy']['proxyType'].downcase
|
|
224
|
-
hash['proxy']['noProxy'] = hash['proxy']['noProxy'].split(', ') if hash['proxy']['noProxy'].is_a?(String)
|
|
225
|
-
end
|
|
226
|
-
when String
|
|
227
|
-
hash[key.to_s] = value
|
|
228
|
-
when Symbol
|
|
229
|
-
hash[camel_case(key.to_s)] = value
|
|
230
|
-
else
|
|
231
|
-
raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
|
|
232
|
-
end
|
|
257
|
+
@capabilities.each_with_object({}) do |(key, value), hash|
|
|
258
|
+
hash[convert_key(key)] = process_capabilities(key, value, hash)
|
|
233
259
|
end
|
|
234
|
-
|
|
235
|
-
hash
|
|
236
260
|
end
|
|
237
261
|
|
|
238
262
|
def to_json(*)
|
|
@@ -253,10 +277,44 @@ module Selenium
|
|
|
253
277
|
|
|
254
278
|
private
|
|
255
279
|
|
|
256
|
-
def
|
|
257
|
-
|
|
280
|
+
def process_capabilities(key, value, hash)
|
|
281
|
+
case value
|
|
282
|
+
when Array
|
|
283
|
+
value.map { |v| process_capabilities(key, v, hash) }
|
|
284
|
+
when Hash
|
|
285
|
+
value.each_with_object({}) do |(k, v), h|
|
|
286
|
+
h[convert_key(k)] = process_capabilities(k, v, h)
|
|
287
|
+
end
|
|
288
|
+
when Capabilities, Options
|
|
289
|
+
value.as_json
|
|
290
|
+
else
|
|
291
|
+
convert_value(key, value)
|
|
292
|
+
end
|
|
258
293
|
end
|
|
259
294
|
|
|
295
|
+
def convert_key(key)
|
|
296
|
+
case key
|
|
297
|
+
when String
|
|
298
|
+
key.to_s
|
|
299
|
+
when Symbol
|
|
300
|
+
self.class.camel_case(key)
|
|
301
|
+
else
|
|
302
|
+
raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def convert_value(key, value)
|
|
307
|
+
case key
|
|
308
|
+
when :platform
|
|
309
|
+
value.to_s.upcase
|
|
310
|
+
when :proxy
|
|
311
|
+
value&.as_json
|
|
312
|
+
when :unhandled_prompt_behavior
|
|
313
|
+
value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
|
|
314
|
+
else
|
|
315
|
+
value
|
|
316
|
+
end
|
|
317
|
+
end
|
|
260
318
|
end # Capabilities
|
|
261
319
|
end # Remote
|
|
262
320
|
end # WebDriver
|
|
@@ -77,11 +77,16 @@ module Selenium
|
|
|
77
77
|
find_elements: [:post, 'session/:session_id/elements'],
|
|
78
78
|
find_child_element: [:post, 'session/:session_id/element/:id/element'],
|
|
79
79
|
find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
|
|
80
|
+
find_shadow_child_element: [:post, 'session/:session_id/shadow/:id/element'],
|
|
81
|
+
find_shadow_child_elements: [:post, 'session/:session_id/shadow/:id/elements'],
|
|
80
82
|
get_active_element: [:get, 'session/:session_id/element/active'],
|
|
83
|
+
get_element_shadow_root: [:get, 'session/:session_id/element/:id/shadow'],
|
|
81
84
|
is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
|
|
82
85
|
get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
|
|
83
86
|
get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
|
|
84
87
|
get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
|
|
88
|
+
get_element_aria_role: [:get, 'session/:session_id/element/:id/computedrole'],
|
|
89
|
+
get_element_aria_label: [:get, 'session/:session_id/element/:id/computedlabel'],
|
|
85
90
|
get_element_text: [:get, 'session/:session_id/element/:id/text'],
|
|
86
91
|
get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
|
|
87
92
|
get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
|
|
@@ -109,6 +114,7 @@ module Selenium
|
|
|
109
114
|
# timeouts
|
|
110
115
|
#
|
|
111
116
|
|
|
117
|
+
get_timeouts: [:get, 'session/:session_id/timeouts'],
|
|
112
118
|
set_timeout: [:post, 'session/:session_id/timeouts'],
|
|
113
119
|
|
|
114
120
|
#
|
|
@@ -117,6 +123,7 @@ module Selenium
|
|
|
117
123
|
|
|
118
124
|
actions: [:post, 'session/:session_id/actions'],
|
|
119
125
|
release_actions: [:delete, 'session/:session_id/actions'],
|
|
126
|
+
print_page: [:post, 'session/:session_id/print'],
|
|
120
127
|
|
|
121
128
|
#
|
|
122
129
|
# Element Operations
|
|
@@ -28,30 +28,33 @@ module Selenium
|
|
|
28
28
|
|
|
29
29
|
class Driver < WebDriver::Driver
|
|
30
30
|
include DriverExtensions::UploadsFiles
|
|
31
|
-
include DriverExtensions::TakesScreenshot
|
|
32
31
|
include DriverExtensions::HasSessionId
|
|
33
|
-
include DriverExtensions::Rotatable
|
|
34
32
|
include DriverExtensions::HasRemoteStatus
|
|
35
|
-
include DriverExtensions::HasWebStorage
|
|
36
|
-
|
|
37
|
-
def initialize(opts = {})
|
|
38
|
-
listener = opts.delete(:listener)
|
|
39
|
-
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
|
|
40
33
|
|
|
34
|
+
def initialize(bridge: nil, listener: nil, **opts)
|
|
35
|
+
desired_capabilities = opts[:desired_capabilities]
|
|
41
36
|
if desired_capabilities.is_a?(Symbol)
|
|
42
|
-
unless Capabilities.respond_to?(desired_capabilities)
|
|
37
|
+
unless Remote::Capabilities.respond_to?(desired_capabilities)
|
|
43
38
|
raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
|
|
44
39
|
end
|
|
45
40
|
|
|
46
|
-
desired_capabilities = Capabilities.__send__(desired_capabilities)
|
|
41
|
+
opts[:desired_capabilities] = Remote::Capabilities.__send__(desired_capabilities)
|
|
47
42
|
end
|
|
43
|
+
opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
|
|
44
|
+
super
|
|
45
|
+
@bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
|
|
46
|
+
end
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
@bridge.create_session(desired_capabilities, opts.delete(:options))
|
|
48
|
+
private
|
|
51
49
|
|
|
52
|
-
|
|
50
|
+
def devtools_url
|
|
51
|
+
capabilities['se:cdp']
|
|
53
52
|
end
|
|
54
53
|
|
|
54
|
+
def devtools_version
|
|
55
|
+
capabilities['se:cdpVersion']&.split('.')&.first ||
|
|
56
|
+
raise(Error::WebDriverError, "DevTools is not supported by the Remote Server")
|
|
57
|
+
end
|
|
55
58
|
end # Driver
|
|
56
59
|
end # Remote
|
|
57
60
|
end # WebDriver
|
|
@@ -28,8 +28,7 @@ module Selenium
|
|
|
28
28
|
class Default < Common
|
|
29
29
|
attr_writer :proxy
|
|
30
30
|
|
|
31
|
-
attr_accessor :open_timeout
|
|
32
|
-
attr_accessor :read_timeout
|
|
31
|
+
attr_accessor :open_timeout, :read_timeout
|
|
33
32
|
|
|
34
33
|
# Initializes object.
|
|
35
34
|
# Warning: Setting {#open_timeout} to non-nil values will cause a separate thread to spawn.
|
|
@@ -39,6 +38,7 @@ module Selenium
|
|
|
39
38
|
def initialize(open_timeout: nil, read_timeout: nil)
|
|
40
39
|
@open_timeout = open_timeout
|
|
41
40
|
@read_timeout = read_timeout
|
|
41
|
+
super()
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def close
|
|
@@ -55,14 +55,18 @@ module Selenium
|
|
|
55
55
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
http.open_timeout = open_timeout
|
|
58
|
+
http.open_timeout = open_timeout if open_timeout
|
|
60
59
|
http.read_timeout = read_timeout if read_timeout
|
|
61
60
|
|
|
62
|
-
http
|
|
61
|
+
start(http)
|
|
62
|
+
http
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
def start(http)
|
|
67
|
+
http.start
|
|
68
|
+
end
|
|
69
|
+
|
|
66
70
|
MAX_RETRIES = 3
|
|
67
71
|
|
|
68
72
|
def request(verb, url, headers, payload, redirects = 0)
|
|
@@ -84,15 +88,15 @@ module Selenium
|
|
|
84
88
|
retries += 1
|
|
85
89
|
sleep 2
|
|
86
90
|
retry
|
|
87
|
-
rescue Errno::EADDRNOTAVAIL =>
|
|
91
|
+
rescue Errno::EADDRNOTAVAIL => e
|
|
88
92
|
# a retry is sometimes needed when the port becomes temporarily unavailable
|
|
89
93
|
raise if retries >= MAX_RETRIES
|
|
90
94
|
|
|
91
95
|
retries += 1
|
|
92
96
|
sleep 2
|
|
93
97
|
retry
|
|
94
|
-
rescue Errno::ECONNREFUSED =>
|
|
95
|
-
raise
|
|
98
|
+
rescue Errno::ECONNREFUSED => e
|
|
99
|
+
raise e.class, "using proxy: #{proxy.http}" if use_proxy?
|
|
96
100
|
|
|
97
101
|
raise
|
|
98
102
|
end
|
|
@@ -123,12 +127,14 @@ module Selenium
|
|
|
123
127
|
def new_http_client
|
|
124
128
|
if use_proxy?
|
|
125
129
|
url = @proxy.http
|
|
126
|
-
|
|
130
|
+
unless proxy.respond_to?(:http) && url
|
|
131
|
+
raise Error::WebDriverError,
|
|
132
|
+
"expected HTTP proxy, got #{@proxy.inspect}"
|
|
133
|
+
end
|
|
127
134
|
|
|
128
135
|
proxy = URI.parse(url)
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
clazz.new(server_url.host, server_url.port)
|
|
137
|
+
Net::HTTP.new(server_url.host, server_url.port, proxy.host, proxy.port, proxy.user, proxy.password)
|
|
132
138
|
else
|
|
133
139
|
Net::HTTP.new server_url.host, server_url.port
|
|
134
140
|
end
|
|
@@ -25,12 +25,22 @@ module Selenium
|
|
|
25
25
|
module Http
|
|
26
26
|
# @api private
|
|
27
27
|
class Persistent < Default
|
|
28
|
+
def initialize(open_timeout: nil, read_timeout: nil)
|
|
29
|
+
WebDriver.logger.deprecate("Selenium::WebDriver::Remote::Http::Persistent",
|
|
30
|
+
id: :http_persistent) { "The default HTTP client now uses persistence." }
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
28
34
|
def close
|
|
29
35
|
@http&.shutdown
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
private
|
|
33
39
|
|
|
40
|
+
def start(*)
|
|
41
|
+
# no need to explicitly start connection
|
|
42
|
+
end
|
|
43
|
+
|
|
34
44
|
def new_http_client
|
|
35
45
|
proxy = nil
|
|
36
46
|
|
|
@@ -42,12 +52,7 @@ module Selenium
|
|
|
42
52
|
proxy = URI.parse(url)
|
|
43
53
|
end
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
|
|
47
|
-
else
|
|
48
|
-
WebDriver.logger.warn 'Support for this version of net-http-persistent is deprecated. Please upgrade.'
|
|
49
|
-
Net::HTTP::Persistent.new 'webdriver', proxy
|
|
50
|
-
end
|
|
55
|
+
Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
def response_for(request)
|
|
@@ -18,14 +18,20 @@
|
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
20
|
require 'uri'
|
|
21
|
-
|
|
22
|
-
require 'selenium/webdriver/remote/bridge'
|
|
23
|
-
require 'selenium/webdriver/remote/driver'
|
|
24
|
-
require 'selenium/webdriver/remote/response'
|
|
25
21
|
require 'selenium/webdriver/remote/server_error'
|
|
26
|
-
require 'selenium/webdriver/remote/http/common'
|
|
27
|
-
require 'selenium/webdriver/remote/http/default'
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
module Selenium
|
|
24
|
+
module WebDriver
|
|
25
|
+
module Remote
|
|
26
|
+
autoload :Bridge, 'selenium/webdriver/remote/bridge'
|
|
27
|
+
autoload :Driver, 'selenium/webdriver/remote/driver'
|
|
28
|
+
autoload :Response, 'selenium/webdriver/remote/response'
|
|
29
|
+
autoload :Capabilities, 'selenium/webdriver/remote/capabilities'
|
|
30
|
+
autoload :COMMANDS, 'selenium/webdriver/remote/commands'
|
|
31
|
+
module Http
|
|
32
|
+
autoload :Common, 'selenium/webdriver/remote/http/common'
|
|
33
|
+
autoload :Default, 'selenium/webdriver/remote/http/default'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -27,44 +27,13 @@ module Selenium
|
|
|
27
27
|
#
|
|
28
28
|
|
|
29
29
|
class Driver < WebDriver::Driver
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def initialize(opts = {})
|
|
35
|
-
opts[:desired_capabilities] = create_capabilities(opts)
|
|
36
|
-
|
|
37
|
-
opts[:url] ||= service_url(opts)
|
|
38
|
-
|
|
39
|
-
listener = opts.delete(:listener)
|
|
40
|
-
desired_capabilities = opts.delete(:desired_capabilities)
|
|
41
|
-
|
|
42
|
-
@bridge = Remote::Bridge.new(opts)
|
|
43
|
-
@bridge.extend Bridge
|
|
44
|
-
@bridge.create_session(desired_capabilities)
|
|
45
|
-
|
|
46
|
-
super(@bridge, listener: listener)
|
|
47
|
-
end
|
|
30
|
+
EXTENSIONS = [DriverExtensions::HasDebugger,
|
|
31
|
+
DriverExtensions::HasApplePermissions,
|
|
32
|
+
DriverExtensions::HasWebStorage].freeze
|
|
48
33
|
|
|
49
34
|
def browser
|
|
50
35
|
:safari
|
|
51
36
|
end
|
|
52
|
-
|
|
53
|
-
def quit
|
|
54
|
-
super
|
|
55
|
-
ensure
|
|
56
|
-
@service&.stop
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
private
|
|
60
|
-
|
|
61
|
-
def create_capabilities(opts = {})
|
|
62
|
-
caps = opts.delete(:desired_capabilities) { Remote::Capabilities.safari }
|
|
63
|
-
options = opts.delete(:options) { Options.new }
|
|
64
|
-
caps.merge!(options.as_json)
|
|
65
|
-
caps
|
|
66
|
-
end
|
|
67
|
-
|
|
68
37
|
end # Driver
|
|
69
38
|
end # Safari
|
|
70
39
|
end # WebDriver
|
|
@@ -20,17 +20,17 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Safari
|
|
23
|
-
module
|
|
23
|
+
module Features
|
|
24
24
|
|
|
25
25
|
# https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/WebDriverEndpointDoc/Commands/Commands.html
|
|
26
|
-
|
|
27
|
-
get_permissions: [:get, '
|
|
28
|
-
set_permissions: [:post, '
|
|
29
|
-
attach_debugger: [:post, '
|
|
26
|
+
SAFARI_COMMANDS = {
|
|
27
|
+
get_permissions: [:get, 'session/:session_id/apple/permissions'],
|
|
28
|
+
set_permissions: [:post, 'session/:session_id/apple/permissions'],
|
|
29
|
+
attach_debugger: [:post, 'session/:session_id/apple/attach_debugger']
|
|
30
30
|
}.freeze
|
|
31
31
|
|
|
32
32
|
def commands(command)
|
|
33
|
-
|
|
33
|
+
SAFARI_COMMANDS[command] || self.class::COMMANDS[command]
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def permissions
|
|
@@ -20,40 +20,21 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Safari
|
|
23
|
-
class Options
|
|
24
|
-
attr_accessor :
|
|
23
|
+
class Options < WebDriver::Options
|
|
24
|
+
attr_accessor :options
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
# Create a new Options instance for W3C-capable versions of Safari.
|
|
28
|
-
#
|
|
29
|
-
# @example
|
|
30
|
-
# options = Selenium::WebDriver::Safari::Options.new(automatic_inspection: true)
|
|
31
|
-
# driver = Selenium::WebDriver.for :safari, options: options
|
|
32
|
-
#
|
|
33
|
-
# @param [Hash] opts the pre-defined options to create the Safari::Options with
|
|
34
|
-
# @option opts [Boolean] :automatic_inspection Preloads Web Inspector and JavaScript debugger. Default is false
|
|
35
|
-
# @option opts [Boolean] :automatic_profiling Preloads Web Inspector and starts a timeline recording. Default is false
|
|
36
|
-
#
|
|
37
26
|
# @see https://developer.apple.com/documentation/webkit/about_webdriver_for_safari
|
|
38
|
-
|
|
27
|
+
CAPABILITIES = {automatic_inspection: 'safari:automaticInspection',
|
|
28
|
+
automatic_profiling: 'safari:automaticProfiling'}.freeze
|
|
29
|
+
BROWSER = 'safari'
|
|
39
30
|
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
# @api private
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
def as_json(*)
|
|
50
|
-
opts = {}
|
|
31
|
+
def add_option(name, value = nil)
|
|
32
|
+
key = name.is_a?(Hash) ? name.keys.first : name
|
|
33
|
+
raise ArgumentError, 'Safari does not support options that are not namespaced' unless key.to_s.include?(':')
|
|
51
34
|
|
|
52
|
-
|
|
53
|
-
opts['safari:automaticProfiling'] = true if @automatic_profiling
|
|
54
|
-
|
|
55
|
-
opts
|
|
35
|
+
super
|
|
56
36
|
end
|
|
37
|
+
|
|
57
38
|
end # Options
|
|
58
39
|
end # Safari
|
|
59
40
|
end # WebDriver
|