selenium-webdriver 3.142.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +406 -4
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +69 -63
  8. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  10. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  11. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  12. data/lib/selenium/webdriver/chrome/driver.rb +26 -70
  13. data/lib/selenium/webdriver/chrome/features.rb +106 -0
  14. data/lib/selenium/webdriver/chrome/options.rb +128 -53
  15. data/lib/selenium/webdriver/chrome/profile.rb +8 -5
  16. data/lib/selenium/webdriver/chrome/service.rb +8 -15
  17. data/lib/selenium/webdriver/chrome.rb +10 -9
  18. data/lib/selenium/webdriver/common/action_builder.rb +97 -249
  19. data/lib/selenium/webdriver/common/driver.rb +112 -23
  20. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  21. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_cdp.rb} +10 -8
  25. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
  26. data/lib/selenium/webdriver/{firefox/util.rb → common/driver_extensions/has_devtools.rb} +16 -19
  27. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  29. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
  32. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  33. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
  34. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  35. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  36. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  37. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  38. data/lib/selenium/webdriver/common/element.rb +82 -22
  39. data/lib/selenium/webdriver/common/error.rb +32 -196
  40. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  41. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
  43. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  44. data/lib/selenium/webdriver/common/logger.rb +50 -15
  45. data/lib/selenium/webdriver/common/manager.rb +15 -15
  46. data/lib/selenium/webdriver/common/options.rb +184 -0
  47. data/lib/selenium/webdriver/common/platform.rb +6 -1
  48. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  49. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  50. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  51. data/lib/selenium/webdriver/common/search_context.rb +7 -3
  52. data/lib/selenium/webdriver/common/service.rb +27 -122
  53. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  54. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  55. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  56. data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
  57. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  58. data/lib/selenium/webdriver/common/target_locator.rb +32 -4
  59. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  60. data/lib/selenium/webdriver/common/wait.rb +1 -1
  61. data/lib/selenium/webdriver/common/window.rb +0 -4
  62. data/lib/selenium/webdriver/common/zipper.rb +3 -9
  63. data/lib/selenium/webdriver/common.rb +24 -17
  64. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  65. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  66. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  67. data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
  68. data/lib/selenium/webdriver/devtools/request.rb +67 -0
  69. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  70. data/lib/selenium/webdriver/devtools.rb +193 -0
  71. data/lib/selenium/webdriver/edge/driver.rb +7 -29
  72. data/lib/selenium/webdriver/{chrome/bridge.rb → edge/features.rb} +16 -22
  73. data/lib/selenium/webdriver/edge/options.rb +11 -48
  74. data/lib/selenium/webdriver/{common/w3c_manager.rb → edge/profile.rb} +7 -19
  75. data/lib/selenium/webdriver/edge/service.rb +10 -26
  76. data/lib/selenium/webdriver/edge.rb +11 -14
  77. data/lib/selenium/webdriver/firefox/driver.rb +31 -19
  78. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  79. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +23 -4
  80. data/lib/selenium/webdriver/firefox/options.rb +71 -50
  81. data/lib/selenium/webdriver/firefox/profile.rb +21 -71
  82. data/lib/selenium/webdriver/firefox/service.rb +5 -9
  83. data/lib/selenium/webdriver/firefox.rb +22 -20
  84. data/lib/selenium/webdriver/ie/driver.rb +1 -47
  85. data/lib/selenium/webdriver/ie/options.rb +15 -46
  86. data/lib/selenium/webdriver/ie/service.rb +13 -15
  87. data/lib/selenium/webdriver/ie.rb +8 -7
  88. data/lib/selenium/webdriver/remote/bridge.rb +561 -86
  89. data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
  90. data/lib/selenium/webdriver/remote/commands.rb +7 -0
  91. data/lib/selenium/webdriver/remote/driver.rb +22 -12
  92. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  93. data/lib/selenium/webdriver/remote/http/default.rb +17 -20
  94. data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
  95. data/lib/selenium/webdriver/remote/response.rb +16 -47
  96. data/lib/selenium/webdriver/remote.rb +15 -12
  97. data/lib/selenium/webdriver/safari/driver.rb +3 -31
  98. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +6 -6
  99. data/lib/selenium/webdriver/safari/options.rb +10 -29
  100. data/lib/selenium/webdriver/safari/service.rb +4 -8
  101. data/lib/selenium/webdriver/safari.rb +17 -9
  102. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  103. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  104. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  105. data/lib/selenium/webdriver/support/color.rb +2 -2
  106. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  107. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  108. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
  109. data/lib/selenium/webdriver/support/guards.rb +95 -0
  110. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  111. data/lib/selenium/webdriver/support/select.rb +3 -3
  112. data/lib/selenium/webdriver/support.rb +1 -0
  113. data/lib/selenium/webdriver/version.rb +1 -1
  114. data/lib/selenium/webdriver.rb +13 -13
  115. data/selenium-webdriver.gemspec +29 -13
  116. metadata +125 -73
  117. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  118. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  119. data/lib/selenium/webdriver/common/keyboard.rb +0 -70
  120. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  121. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  122. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  123. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  124. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  125. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  126. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  127. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  128. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  129. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  130. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  131. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  132. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  133. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  134. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  135. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  136. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  137. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -20,32 +20,35 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
+
23
24
  #
24
25
  # Specification of the desired and/or actual capabilities of the browser that the
25
26
  # server is being asked to create.
26
27
  #
28
+
27
29
  class Capabilities
28
- DEFAULTS = {
29
- browser_name: '',
30
- version: '',
31
- platform: :any,
32
- javascript_enabled: false,
33
- css_selectors_enabled: false,
34
- takes_screenshot: false,
35
- native_events: false,
36
- rotatable: false,
37
- firefox_profile: nil,
38
- proxy: nil
39
- }.freeze
40
-
41
- DEFAULTS.each_key do |key|
42
- if key != :javascript_enabled
43
- define_method key do
44
- @capabilities.fetch(key)
45
- end
46
- end
47
30
 
48
- next if key == :proxy
31
+ KNOWN = [
32
+ :browser_name,
33
+ :browser_version,
34
+ :platform_name,
35
+ :accept_insecure_certs,
36
+ :page_load_strategy,
37
+ :proxy,
38
+ :set_window_rect,
39
+ :timeouts,
40
+ :unhandled_prompt_behavior,
41
+ :strict_file_interactability,
42
+ :web_socket_url,
43
+
44
+ # remote-specific (webdriver.remote.sessionid)
45
+ :remote_session_id
46
+ ].freeze
47
+
48
+ (KNOWN - %i[proxy timeouts]).each do |key|
49
+ define_method key do
50
+ @capabilities[key]
51
+ end
49
52
 
50
53
  define_method "#{key}=" do |value|
51
54
  @capabilities[key] = value
@@ -53,19 +56,13 @@ module Selenium
53
56
  end
54
57
 
55
58
  #
56
- # Returns javascript_enabled capability.
57
- # It is true if not set explicitly.
59
+ # Backward compatibility
58
60
  #
59
- def javascript_enabled
60
- javascript_enabled = @capabilities.fetch(:javascript_enabled)
61
- javascript_enabled.nil? ? true : javascript_enabled
62
- end
63
61
 
64
- alias_method :css_selectors_enabled?, :css_selectors_enabled
65
- alias_method :javascript_enabled?, :javascript_enabled
66
- alias_method :native_events?, :native_events
67
- alias_method :takes_screenshot?, :takes_screenshot
68
- alias_method :rotatable?, :rotatable
62
+ alias_method :version, :browser_version
63
+ alias_method :version=, :browser_version=
64
+ alias_method :platform, :platform_name
65
+ alias_method :platform=, :platform_name=
69
66
 
70
67
  #
71
68
  # Convenience methods for the common choices.
@@ -74,80 +71,50 @@ module Selenium
74
71
  class << self
75
72
  def chrome(opts = {})
76
73
  new({
77
- browser_name: 'chrome',
78
- javascript_enabled: true,
79
- css_selectors_enabled: true
74
+ browser_name: 'chrome'
80
75
  }.merge(opts))
81
76
  end
82
77
 
83
78
  def edge(opts = {})
84
79
  new({
85
- browser_name: 'MicrosoftEdge',
86
- platform: :windows
80
+ browser_name: 'MicrosoftEdge'
87
81
  }.merge(opts))
88
82
  end
83
+ alias_method :microsoftedge, :edge
89
84
 
90
85
  def firefox(opts = {})
91
- opts[:browser_version] = opts.delete(:version) if opts.key?(:version)
92
- opts[:platform_name] = opts.delete(:platform) if opts.key?(:platform)
93
- opts[:timeouts] = {}
94
- opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
95
- opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
96
- opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
97
- new({browser_name: 'firefox', marionette: true}.merge(opts))
98
- end
99
-
100
- def firefox_legacy(opts = {})
101
86
  new({
102
- browser_name: 'firefox',
103
- javascript_enabled: true,
104
- takes_screenshot: true,
105
- css_selectors_enabled: true
87
+ browser_name: 'firefox'
106
88
  }.merge(opts))
107
89
  end
90
+ alias_method :ff, :firefox
108
91
 
109
- def htmlunit(opts = {})
92
+ def safari(opts = {})
110
93
  new({
111
- browser_name: 'htmlunit'
94
+ browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
112
95
  }.merge(opts))
113
96
  end
114
97
 
115
- def htmlunitwithjs(opts = {})
98
+ def htmlunit(opts = {})
116
99
  new({
117
- browser_name: 'htmlunit',
118
- javascript_enabled: true
100
+ browser_name: 'htmlunit'
119
101
  }.merge(opts))
120
102
  end
121
103
 
122
104
  def internet_explorer(opts = {})
123
105
  new({
124
106
  browser_name: 'internet explorer',
125
- platform: :windows,
126
- takes_screenshot: true,
127
- css_selectors_enabled: true,
128
- native_events: true
107
+ platform_name: :windows
129
108
  }.merge(opts))
130
109
  end
131
110
  alias_method :ie, :internet_explorer
132
111
 
133
- def phantomjs(opts = {})
134
- WebDriver.logger.deprecate 'Selenium support for PhantomJS', 'headless Chrome/Firefox or HTMLUnit'
135
- new({
136
- browser_name: 'phantomjs',
137
- javascript_enabled: true,
138
- takes_screenshot: true,
139
- css_selectors_enabled: true
140
- }.merge(opts))
112
+ def always_match(capabilities)
113
+ new(always_match: capabilities)
141
114
  end
142
115
 
143
- def safari(opts = {})
144
- new({
145
- browser_name: 'safari',
146
- platform: :mac,
147
- javascript_enabled: true,
148
- takes_screenshot: true,
149
- css_selectors_enabled: true
150
- }.merge(opts))
116
+ def first_match(*capabilities)
117
+ new(first_match: capabilities)
151
118
  end
152
119
 
153
120
  #
@@ -156,41 +123,61 @@ module Selenium
156
123
 
157
124
  def json_create(data)
158
125
  data = data.dup
159
-
160
126
  caps = new
161
- caps.browser_name = data.delete('browserName')
162
- caps.version = data.delete('version')
163
- caps.platform = data.delete('platform').downcase.tr(' ', '_').to_sym if data.key?('platform')
164
- caps.javascript_enabled = data.delete('javascriptEnabled')
165
- caps.css_selectors_enabled = data.delete('cssSelectorsEnabled')
166
- caps.takes_screenshot = data.delete('takesScreenshot')
167
- caps.native_events = data.delete('nativeEvents')
168
- caps.rotatable = data.delete('rotatable')
169
- caps.proxy = Proxy.json_create(data['proxy']) if data.key?('proxy') && !data['proxy'].empty?
127
+
128
+ process_timeouts(caps, data.delete('timeouts'))
129
+
130
+ if data.key?('proxy')
131
+ proxy = data.delete('proxy')
132
+ caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?
133
+ end
134
+
135
+ # Remote Server Specific
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
170
144
 
171
145
  # any remaining pairs will be added as is, with no conversion
172
146
  caps.merge!(data)
173
147
 
174
148
  caps
175
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
176
164
  end
177
165
 
178
166
  #
179
- # @option :browser_name [String] required browser name
180
- # @option :version [String] required browser version number
181
- # @option :platform [Symbol] one of :any, :win, :mac, or :x
182
- # @option :javascript_enabled [Boolean] does the driver have javascript enabled?
183
- # @option :css_selectors_enabled [Boolean] does the driver support CSS selectors?
184
- # @option :takes_screenshot [Boolean] can this driver take screenshots?
185
- # @option :native_events [Boolean] does this driver use native events?
186
- # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
167
+ # @param [Hash] opts
168
+ # @option :browser_name [String] required browser name
169
+ # @option :browser_version [String] required browser version number
170
+ # @option :platform_name [Symbol] one of :any, :win, :mac, or :x
171
+ # @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?
172
+ # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
187
173
  #
188
174
  # @api public
189
175
  #
190
176
 
191
177
  def initialize(opts = {})
192
- @capabilities = DEFAULTS.merge(opts)
193
- self.proxy = opts.delete(:proxy)
178
+ @capabilities = {}
179
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
180
+ @capabilities.merge!(opts)
194
181
  end
195
182
 
196
183
  #
@@ -215,6 +202,10 @@ module Selenium
215
202
  end
216
203
  end
217
204
 
205
+ def proxy
206
+ @capabilities[:proxy]
207
+ end
208
+
218
209
  def proxy=(proxy)
219
210
  case proxy
220
211
  when Hash
@@ -226,37 +217,46 @@ module Selenium
226
217
  end
227
218
  end
228
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
+
229
252
  #
230
253
  # @api private
231
254
  #
232
255
 
233
- def as_json(*) # rubocop:disable Metrics/CyclomaticComplexity
234
- hash = {}
235
-
236
- @capabilities.each do |key, value|
237
- case key
238
- when :platform
239
- hash['platform'] = value.to_s.upcase
240
- when :firefox_profile
241
- if value
242
- WebDriver.logger.deprecate(':firefox_profile capabilitiy', 'Selenium::WebDriver::Firefox::Options#profile')
243
- hash['firefox_profile'] = value.as_json['zip']
244
- end
245
- when :proxy
246
- hash['proxy'] = value.as_json if value
247
- when String, :firefox_binary
248
- if key == :firefox_binary && value
249
- WebDriver.logger.deprecate(':firefox_binary capabilitiy', 'Selenium::WebDriver::Firefox::Options#binary')
250
- end
251
- hash[key.to_s] = value
252
- when Symbol
253
- hash[camel_case(key.to_s)] = value
254
- else
255
- raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
256
- end
256
+ def as_json(*)
257
+ @capabilities.each_with_object({}) do |(key, value), hash|
258
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
257
259
  end
258
-
259
- hash
260
260
  end
261
261
 
262
262
  def to_json(*)
@@ -268,6 +268,7 @@ module Selenium
268
268
 
269
269
  as_json == other.as_json
270
270
  end
271
+
271
272
  alias_method :eql?, :==
272
273
 
273
274
  protected
@@ -276,8 +277,43 @@ module Selenium
276
277
 
277
278
  private
278
279
 
279
- def camel_case(str)
280
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
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
293
+ end
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
281
317
  end
282
318
  end # Capabilities
283
319
  end # Remote
@@ -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,23 +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
- @bridge = Bridge.handshake(opts)
40
- if @bridge.dialect == :oss
41
- extend DriverExtensions::HasTouchScreen
42
- extend DriverExtensions::HasLocation
43
- extend DriverExtensions::HasNetworkConnection
33
+
34
+ def initialize(bridge: nil, listener: nil, **opts)
35
+ desired_capabilities = opts[:desired_capabilities]
36
+ if desired_capabilities.is_a?(Symbol)
37
+ unless Remote::Capabilities.respond_to?(desired_capabilities)
38
+ raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
39
+ end
40
+
41
+ opts[:desired_capabilities] = Remote::Capabilities.__send__(desired_capabilities)
44
42
  end
45
- super(@bridge, listener: listener)
43
+ opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
44
+ super
45
+ @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
46
+ end
47
+
48
+ private
49
+
50
+ def devtools_url
51
+ capabilities['se:cdp']
46
52
  end
47
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
48
58
  end # Driver
49
59
  end # Remote
50
60
  end # WebDriver
@@ -30,13 +30,8 @@ module Selenium
30
30
  'User-Agent' => "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
31
31
  }.freeze
32
32
 
33
- attr_accessor :timeout
34
33
  attr_writer :server_url
35
34
 
36
- def initialize
37
- @timeout = nil
38
- end
39
-
40
35
  def quit_errors
41
36
  [IOError]
42
37
  end
@@ -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,15 +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
42
- end
43
-
44
- # Maintaining backward compatibility.
45
- # @param [Numeric] value - Timeout in seconds to apply to both open timeout and read timeouts.
46
- # @deprecated Please set the specific desired timeout {#read_timeout} or {#open_timeout} directly.
47
- def timeout=(value)
48
- WebDriver.logger.deprecate ':timeout=', '#read_timeout= and #open_timeout='
49
- self.open_timeout = value
50
- self.read_timeout = value
41
+ super()
51
42
  end
52
43
 
53
44
  def close
@@ -64,14 +55,18 @@ module Selenium
64
55
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
56
  end
66
57
 
67
- # Defaulting open_timeout to nil to be consistent with Ruby 2.2 and earlier.
68
- http.open_timeout = open_timeout
58
+ http.open_timeout = open_timeout if open_timeout
69
59
  http.read_timeout = read_timeout if read_timeout
70
60
 
71
- http.start
61
+ start(http)
62
+ http
72
63
  end
73
64
  end
74
65
 
66
+ def start(http)
67
+ http.start
68
+ end
69
+
75
70
  MAX_RETRIES = 3
76
71
 
77
72
  def request(verb, url, headers, payload, redirects = 0)
@@ -93,15 +88,15 @@ module Selenium
93
88
  retries += 1
94
89
  sleep 2
95
90
  retry
96
- rescue Errno::EADDRNOTAVAIL => ex
91
+ rescue Errno::EADDRNOTAVAIL => e
97
92
  # a retry is sometimes needed when the port becomes temporarily unavailable
98
93
  raise if retries >= MAX_RETRIES
99
94
 
100
95
  retries += 1
101
96
  sleep 2
102
97
  retry
103
- rescue Errno::ECONNREFUSED => ex
104
- raise ex.class, "using proxy: #{proxy.http}" if use_proxy?
98
+ rescue Errno::ECONNREFUSED => e
99
+ raise e.class, "using proxy: #{proxy.http}" if use_proxy?
105
100
 
106
101
  raise
107
102
  end
@@ -132,12 +127,14 @@ module Selenium
132
127
  def new_http_client
133
128
  if use_proxy?
134
129
  url = @proxy.http
135
- raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}" unless proxy.respond_to?(:http) && url
130
+ unless proxy.respond_to?(:http) && url
131
+ raise Error::WebDriverError,
132
+ "expected HTTP proxy, got #{@proxy.inspect}"
133
+ end
136
134
 
137
135
  proxy = URI.parse(url)
138
136
 
139
- clazz = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password)
140
- 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)
141
138
  else
142
139
  Net::HTTP.new server_url.host, server_url.port
143
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
- if Net::HTTP::Persistent::VERSION >= '3'
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)