selenium-webdriver 3.142.1 → 4.1.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.
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)