selenium-webdriver 4.1.0 → 4.8.1

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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +182 -1
  3. data/LICENSE +1 -1
  4. data/NOTICE +1 -1
  5. data/bin/linux/selenium-manager +0 -0
  6. data/bin/macos/selenium-manager +0 -0
  7. data/bin/windows/selenium-manager.exe +0 -0
  8. data/lib/selenium/server.rb +35 -26
  9. data/lib/selenium/webdriver/atoms/findElements.js +0 -0
  10. data/lib/selenium/webdriver/atoms/getAttribute.js +0 -0
  11. data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
  12. data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
  13. data/lib/selenium/webdriver/atoms.rb +2 -3
  14. data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
  15. data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
  16. data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
  17. data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
  18. data/lib/selenium/webdriver/bidi/log/filter_by.rb +40 -0
  19. data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
  20. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
  21. data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
  22. data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
  23. data/lib/selenium/webdriver/bidi/session.rb +51 -0
  24. data/lib/selenium/webdriver/bidi.rb +56 -0
  25. data/lib/selenium/webdriver/chrome/driver.rb +19 -28
  26. data/lib/selenium/webdriver/chrome/features.rb +6 -68
  27. data/lib/selenium/webdriver/chrome/options.rb +3 -223
  28. data/lib/selenium/webdriver/chrome/profile.rb +3 -83
  29. data/lib/selenium/webdriver/chrome/service.rb +4 -19
  30. data/lib/selenium/webdriver/chrome.rb +0 -14
  31. data/lib/selenium/webdriver/chromium/driver.rb +61 -0
  32. data/lib/selenium/webdriver/chromium/features.rb +103 -0
  33. data/lib/selenium/webdriver/chromium/options.rb +261 -0
  34. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  35. data/lib/selenium/webdriver/chromium/service.rb +42 -0
  36. data/lib/selenium/webdriver/chromium.rb +32 -0
  37. data/lib/selenium/webdriver/common/action_builder.rb +72 -22
  38. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  39. data/lib/selenium/webdriver/common/driver.rb +50 -70
  40. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  41. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
  42. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  43. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
  44. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +10 -5
  46. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -1
  47. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
  48. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -4
  49. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  50. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
  51. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +1 -2
  53. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -2
  54. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
  55. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -69
  56. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
  57. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -3
  58. data/lib/selenium/webdriver/common/element.rb +8 -8
  59. data/lib/selenium/webdriver/common/error.rb +1 -3
  60. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  61. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  62. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
  63. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  64. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
  65. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  66. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  67. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  68. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
  69. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  70. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  71. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  72. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  73. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  74. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  75. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  76. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  77. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  78. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
  79. data/lib/selenium/webdriver/common/keys.rb +1 -0
  80. data/lib/selenium/webdriver/common/logger.rb +10 -2
  81. data/lib/selenium/webdriver/common/manager.rb +0 -27
  82. data/lib/selenium/webdriver/common/options.rb +32 -17
  83. data/lib/selenium/webdriver/common/platform.rb +8 -5
  84. data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
  85. data/lib/selenium/webdriver/common/proxy.rb +1 -1
  86. data/lib/selenium/webdriver/common/search_context.rb +0 -6
  87. data/lib/selenium/webdriver/common/selenium_manager.rb +89 -0
  88. data/lib/selenium/webdriver/common/service.rb +16 -8
  89. data/lib/selenium/webdriver/common/service_manager.rb +4 -13
  90. data/lib/selenium/webdriver/common/shadow_root.rb +2 -3
  91. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  92. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  93. data/lib/selenium/webdriver/common/takes_screenshot.rb +2 -3
  94. data/lib/selenium/webdriver/common/target_locator.rb +2 -3
  95. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  96. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  97. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  98. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  99. data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
  100. data/lib/selenium/webdriver/common/window.rb +6 -6
  101. data/lib/selenium/webdriver/common/zipper.rb +1 -1
  102. data/lib/selenium/webdriver/common.rb +19 -3
  103. data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
  104. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
  105. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
  106. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  107. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
  108. data/lib/selenium/webdriver/devtools/request.rb +1 -3
  109. data/lib/selenium/webdriver/devtools/response.rb +1 -3
  110. data/lib/selenium/webdriver/devtools.rb +6 -113
  111. data/lib/selenium/webdriver/edge/driver.rb +20 -3
  112. data/lib/selenium/webdriver/edge/features.rb +4 -4
  113. data/lib/selenium/webdriver/edge/options.rb +3 -5
  114. data/lib/selenium/webdriver/edge/profile.rb +2 -2
  115. data/lib/selenium/webdriver/edge/service.rb +2 -2
  116. data/lib/selenium/webdriver/firefox/driver.rb +20 -2
  117. data/lib/selenium/webdriver/firefox/features.rb +6 -6
  118. data/lib/selenium/webdriver/firefox/options.rb +9 -3
  119. data/lib/selenium/webdriver/firefox/profile.rb +7 -11
  120. data/lib/selenium/webdriver/firefox/service.rb +0 -1
  121. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  122. data/lib/selenium/webdriver/firefox.rb +1 -14
  123. data/lib/selenium/webdriver/ie/driver.rb +20 -1
  124. data/lib/selenium/webdriver/ie/service.rb +1 -2
  125. data/lib/selenium/webdriver/ie.rb +0 -14
  126. data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +15 -8
  127. data/lib/selenium/webdriver/remote/bridge.rb +59 -30
  128. data/lib/selenium/webdriver/remote/capabilities.rb +34 -12
  129. data/lib/selenium/webdriver/remote/driver.rb +14 -15
  130. data/lib/selenium/webdriver/remote/http/curb.rb +0 -2
  131. data/lib/selenium/webdriver/remote/http/default.rb +7 -12
  132. data/lib/selenium/webdriver/remote/response.rb +2 -3
  133. data/lib/selenium/webdriver/remote.rb +0 -1
  134. data/lib/selenium/webdriver/safari/driver.rb +20 -1
  135. data/lib/selenium/webdriver/safari/features.rb +0 -2
  136. data/lib/selenium/webdriver/safari/options.rb +5 -1
  137. data/lib/selenium/webdriver/safari.rb +1 -15
  138. data/lib/selenium/webdriver/support/color.rb +20 -20
  139. data/lib/selenium/webdriver/support/guards/guard.rb +0 -2
  140. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -3
  141. data/lib/selenium/webdriver/support/guards.rb +1 -1
  142. data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
  143. data/lib/selenium/webdriver/support/select.rb +3 -1
  144. data/lib/selenium/webdriver/version.rb +1 -1
  145. data/lib/selenium/webdriver.rb +4 -4
  146. data/selenium-webdriver.gemspec +13 -11
  147. metadata +68 -59
  148. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
  149. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
  150. data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
@@ -26,11 +26,11 @@ module Selenium
26
26
  VALID_PREFERENCE_TYPES = [TrueClass, FalseClass, Integer, Float, String].freeze
27
27
 
28
28
  DEFAULT_PREFERENCES = {
29
- "browser.newtabpage.enabled" => false,
30
- "browser.startup.homepage" => "about:blank",
31
- "browser.usedOnWindows10.introURL" => "about:blank",
32
- "network.captive-portal-service.enabled" => false,
33
- "security.csp.enable" => false
29
+ 'browser.newtabpage.enabled' => false,
30
+ 'browser.startup.homepage' => 'about:blank',
31
+ 'browser.usedOnWindows10.introURL' => 'about:blank',
32
+ 'network.captive-portal-service.enabled' => false,
33
+ 'security.csp.enable' => false
34
34
  }.freeze
35
35
 
36
36
  attr_reader :name, :log_file
@@ -96,7 +96,7 @@ module Selenium
96
96
  raise TypeError, "expected one of #{VALID_PREFERENCE_TYPES.inspect}, got #{value.inspect}:#{value.class}"
97
97
  end
98
98
 
99
- if value.is_a?(String) && stringified?(value)
99
+ if value.is_a?(String) && Util.stringified?(value)
100
100
  raise ArgumentError, "preference values must be plain strings: #{key.inspect} => #{value.inspect}"
101
101
  end
102
102
 
@@ -143,7 +143,7 @@ module Selenium
143
143
  end
144
144
  end
145
145
 
146
- alias_method :as_json, :encoded
146
+ alias as_json encoded
147
147
 
148
148
  private
149
149
 
@@ -221,10 +221,6 @@ module Selenium
221
221
  end
222
222
  end
223
223
  end
224
-
225
- def stringified?(str)
226
- /^".*"$/.match?(str)
227
- end
228
224
  end # Profile
229
225
  end # Firefox
230
226
  end # WebDriver
@@ -32,7 +32,6 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # NOTE: This processing is deprecated
36
35
  def extract_service_args(driver_opts)
37
36
  driver_args = super
38
37
  driver_opts = driver_opts.dup
@@ -0,0 +1,46 @@
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
+ module Firefox
23
+ # @api private
24
+ module Util
25
+ module_function
26
+
27
+ def app_data_path
28
+ case Platform.os
29
+ when :windows
30
+ "#{ENV.fetch('APPDATA')}\\Mozilla\\Firefox"
31
+ when :macosx
32
+ "#{Platform.home}/Library/Application Support/Firefox"
33
+ when :unix, :linux
34
+ "#{Platform.home}/.mozilla/firefox"
35
+ else
36
+ raise "Unknown os: #{Platform.os}"
37
+ end
38
+ end
39
+
40
+ def stringified?(str)
41
+ str =~ /^".*"$/
42
+ end
43
+ end # Util
44
+ end # Firefox
45
+ end # WebDriver
46
+ end # Selenium
@@ -24,6 +24,7 @@ require 'rexml/document'
24
24
  module Selenium
25
25
  module WebDriver
26
26
  module Firefox
27
+ autoload :Util, 'selenium/webdriver/firefox/util'
27
28
  autoload :Extension, 'selenium/webdriver/firefox/extension'
28
29
  autoload :ProfilesIni, 'selenium/webdriver/firefox/profiles_ini'
29
30
  autoload :Profile, 'selenium/webdriver/firefox/profile'
@@ -41,20 +42,6 @@ module Selenium
41
42
  # until WebDriver Bidi is available.
42
43
  DEVTOOLS_VERSION = 85
43
44
 
44
- def self.driver_path=(path)
45
- WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path=',
46
- 'Selenium::WebDriver::Firefox::Service#driver_path=',
47
- id: :driver_path
48
- Selenium::WebDriver::Firefox::Service.driver_path = path
49
- end
50
-
51
- def self.driver_path
52
- WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path',
53
- 'Selenium::WebDriver::Firefox::Service#driver_path',
54
- id: :driver_path
55
- Selenium::WebDriver::Firefox::Service.driver_path
56
- end
57
-
58
45
  def self.path=(path)
59
46
  Platform.assert_executable path
60
47
  @path = path
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module IE
23
-
24
23
  #
25
24
  # Driver implementation for Internet Explorer supporting
26
25
  # both OSS and W3C dialects of JSON wire protocol.
@@ -30,9 +29,29 @@ module Selenium
30
29
  class Driver < WebDriver::Driver
31
30
  EXTENSIONS = [DriverExtensions::HasWebStorage].freeze
32
31
 
32
+ def initialize(capabilities: nil, options: nil, service: nil, url: nil, **opts)
33
+ raise ArgumentError, "Can't initialize #{self.class} with :url" if url
34
+
35
+ caps = process_options(options, capabilities)
36
+ url = service_url(service || Service.ie)
37
+ super(caps: caps, url: url, **opts)
38
+ end
39
+
33
40
  def browser
34
41
  :internet_explorer
35
42
  end
43
+
44
+ private
45
+
46
+ def process_options(options, capabilities)
47
+ if options && !options.is_a?(Options)
48
+ raise ArgumentError, ":options must be an instance of #{Options}"
49
+ elsif options.nil? && capabilities.nil?
50
+ options = Options.new
51
+ end
52
+
53
+ super(options, capabilities)
54
+ end
36
55
  end # Driver
37
56
  end # IE
38
57
  end # WebDriver
@@ -32,7 +32,6 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # NOTE: This processing is deprecated
36
35
  def extract_service_args(driver_opts)
37
36
  driver_args = super
38
37
  driver_opts = driver_opts.dup
@@ -43,7 +42,7 @@ module Selenium
43
42
  end
44
43
  driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key?(:host)
45
44
  driver_args << "--extract_path=#{driver_opts[:extract_path]}" if driver_opts.key?(:extract_path)
46
- driver_args << "--silent" if driver_opts[:silent] == true
45
+ driver_args << '--silent' if driver_opts[:silent] == true
47
46
  driver_args
48
47
  end
49
48
  end # Server
@@ -23,20 +23,6 @@ module Selenium
23
23
  autoload :Driver, 'selenium/webdriver/ie/driver'
24
24
  autoload :Options, 'selenium/webdriver/ie/options'
25
25
  autoload :Service, 'selenium/webdriver/ie/service'
26
-
27
- def self.driver_path=(path)
28
- WebDriver.logger.deprecate 'Selenium::WebDriver::IE#driver_path=',
29
- 'Selenium::WebDriver::IE::Service#driver_path=',
30
- id: :driver_path
31
- Selenium::WebDriver::IE::Service.driver_path = path
32
- end
33
-
34
- def self.driver_path
35
- WebDriver.logger.deprecate 'Selenium::WebDriver::IE#driver_path',
36
- 'Selenium::WebDriver::IE::Service#driver_path',
37
- id: :driver_path
38
- Selenium::WebDriver::IE::Service.driver_path
39
- end
40
26
  end # IE
41
27
  end # WebDriver
42
28
  end # Selenium
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
-
24
23
  #
25
24
  # https://w3c.github.io/webdriver/#endpoints
26
25
  # @api private
@@ -60,10 +59,6 @@ module Selenium
60
59
  fullscreen_window: [:post, 'session/:session_id/window/fullscreen'],
61
60
  minimize_window: [:post, 'session/:session_id/window/minimize'],
62
61
  maximize_window: [:post, 'session/:session_id/window/maximize'],
63
- set_window_size: [:post, 'session/:session_id/window/size'],
64
- get_window_size: [:get, 'session/:session_id/window/size'],
65
- set_window_position: [:post, 'session/:session_id/window/position'],
66
- get_window_position: [:get, 'session/:session_id/window/position'],
67
62
  set_window_rect: [:post, 'session/:session_id/window/rect'],
68
63
  get_window_rect: [:get, 'session/:session_id/window/rect'],
69
64
  switch_to_frame: [:post, 'session/:session_id/frame'],
@@ -130,7 +125,6 @@ module Selenium
130
125
  #
131
126
 
132
127
  element_click: [:post, 'session/:session_id/element/:id/click'],
133
- element_tap: [:post, 'session/:session_id/element/:id/tap'],
134
128
  element_clear: [:post, 'session/:session_id/element/:id/clear'],
135
129
  element_send_keys: [:post, 'session/:session_id/element/:id/value'],
136
130
 
@@ -154,9 +148,22 @@ module Selenium
154
148
  # server extensions
155
149
  #
156
150
 
157
- upload_file: [:post, 'session/:session_id/se/file']
158
- }.freeze
151
+ upload_file: [:post, 'session/:session_id/se/file'],
159
152
 
153
+ #
154
+ # virtual-authenticator
155
+ #
156
+
157
+ add_virtual_authenticator: [:post, 'session/:session_id/webauthn/authenticator'],
158
+ remove_virtual_authenticator: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId'],
159
+ add_credential: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/credential'],
160
+ get_credentials: [:get, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'],
161
+ remove_credential: [:delete,
162
+ 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials/:credentialId'],
163
+ remove_all_credentials: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'],
164
+ set_user_verified: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/uv']
165
+
166
+ }.freeze
160
167
  end # Bridge
161
168
  end # Remote
162
169
  end # WebDriver
@@ -21,6 +21,7 @@ module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
23
  class Bridge
24
+ autoload :COMMANDS, 'selenium/webdriver/remote/bridge/commands'
24
25
  include Atoms
25
26
 
26
27
  PORT = 4444
@@ -30,8 +31,8 @@ module Selenium
30
31
 
31
32
  #
32
33
  # Initializes the bridge with the given server URL
33
- # @param [String, URI] :url url for the remote server
34
- # @param [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
34
+ # @param [String, URI] url url for the remote server
35
+ # @param [Object] http_client an HTTP client instance that implements the same protocol as Http::Default
35
36
  # @api private
36
37
  #
37
38
 
@@ -118,7 +119,7 @@ module Selenium
118
119
  end
119
120
 
120
121
  def alert=(keys)
121
- execute :send_alert_text, {}, {value: keys.split(//), text: keys}
122
+ execute :send_alert_text, {}, {value: keys.chars, text: keys}
122
123
  end
123
124
 
124
125
  def alert_text
@@ -146,9 +147,7 @@ module Selenium
146
147
  end
147
148
 
148
149
  def page_source
149
- execute_script('var source = document.documentElement.outerHTML;' \
150
- 'if (!source) { source = new XMLSerializer().serializeToString(document); }' \
151
- 'return source;')
150
+ execute :get_page_source
152
151
  end
153
152
 
154
153
  #
@@ -188,6 +187,7 @@ module Selenium
188
187
  execute :delete_session
189
188
  http.close
190
189
  rescue *QUIT_ERRORS
190
+ nil
191
191
  end
192
192
 
193
193
  def close
@@ -369,21 +369,10 @@ module Selenium
369
369
  # actions
370
370
  #
371
371
 
372
- def action(async = false)
373
- ActionBuilder.new self,
374
- Interactions.pointer(:mouse, name: 'mouse'),
375
- Interactions.key('keyboard'),
376
- async
377
- end
378
- alias_method :actions, :action
379
-
380
- def mouse
381
- raise Error::UnsupportedOperationError, '#mouse is no longer supported, use #action instead'
382
- end
383
-
384
- def keyboard
385
- raise Error::UnsupportedOperationError, '#keyboard is no longer supported, use #action instead'
372
+ def action(async: false, devices: [], duration: 250)
373
+ ActionBuilder.new self, async: async, devices: devices, duration: duration
386
374
  end
375
+ alias actions action
387
376
 
388
377
  def send_actions(data)
389
378
  execute :actions, {}, {actions: data}
@@ -405,15 +394,15 @@ module Selenium
405
394
  # TODO: rework file detectors before Selenium 4.0
406
395
  if @file_detector
407
396
  local_files = keys.first&.split("\n")&.map { |key| @file_detector.call(Array(key)) }&.compact
408
- if local_files.any?
397
+ if local_files&.any?
409
398
  keys = local_files.map { |local_file| upload(local_file) }
410
399
  keys = Array(keys.join("\n"))
411
400
  end
412
401
  end
413
402
 
414
403
  # Keep .split(//) for backward compatibility for now
415
- text = keys.join('')
416
- execute :element_send_keys, {id: element}, {value: text.split(//), text: text}
404
+ text = keys.join
405
+ execute :element_send_keys, {id: element}, {value: text.chars, text: text}
417
406
  end
418
407
 
419
408
  def upload(local_file)
@@ -430,10 +419,19 @@ module Selenium
430
419
  end
431
420
 
432
421
  def submit_element(element)
433
- form = find_element_by('xpath', "./ancestor-or-self::form", [:element, element])
434
- execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
435
- "e.initEvent('submit', true, true);" \
436
- 'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
422
+ script = "/* submitForm */ var form = arguments[0];\n" \
423
+ "while (form.nodeName != \"FORM\" && form.parentNode) {\n " \
424
+ "form = form.parentNode;\n" \
425
+ "}\n" \
426
+ "if (!form) { throw Error('Unable to find containing form element'); }\n" \
427
+ "if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" \
428
+ "var e = form.ownerDocument.createEvent('Event');\n" \
429
+ "e.initEvent('submit', true, true);\n" \
430
+ "if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n"
431
+
432
+ execute_script(script, Element::ELEMENT_KEY => element)
433
+ rescue Error::JavascriptError
434
+ raise Error::UnsupportedOperationError, 'To submit an element, it must be nested inside a form element'
437
435
  end
438
436
 
439
437
  #
@@ -521,7 +519,7 @@ module Selenium
521
519
  Element.new self, element_id_from(execute(:get_active_element))
522
520
  end
523
521
 
524
- alias_method :switch_to_active_element, :active_element
522
+ alias switch_to_active_element active_element
525
523
 
526
524
  def find_element_by(how, what, parent_ref = [])
527
525
  how, what = convert_locator(how, what)
@@ -564,6 +562,39 @@ module Selenium
564
562
  ShadowRoot.new self, shadow_root_id_from(id)
565
563
  end
566
564
 
565
+ #
566
+ # virtual-authenticator
567
+ #
568
+
569
+ def add_virtual_authenticator(options)
570
+ authenticator_id = execute :add_virtual_authenticator, {}, options.as_json
571
+ VirtualAuthenticator.new(self, authenticator_id, options)
572
+ end
573
+
574
+ def remove_virtual_authenticator(id)
575
+ execute :remove_virtual_authenticator, {authenticatorId: id}
576
+ end
577
+
578
+ def add_credential(credential, id)
579
+ execute :add_credential, {authenticatorId: id}, credential
580
+ end
581
+
582
+ def credentials(authenticator_id)
583
+ execute :get_credentials, {authenticatorId: authenticator_id}
584
+ end
585
+
586
+ def remove_credential(credential_id, authenticator_id)
587
+ execute :remove_credential, {credentialId: credential_id, authenticatorId: authenticator_id}
588
+ end
589
+
590
+ def remove_all_credentials(authenticator_id)
591
+ execute :remove_all_credentials, {authenticatorId: authenticator_id}
592
+ end
593
+
594
+ def user_verified(verified, authenticator_id)
595
+ execute :set_user_verified, {authenticatorId: authenticator_id}, {isUserVerified: verified}
596
+ end
597
+
567
598
  private
568
599
 
569
600
  #
@@ -639,8 +670,6 @@ module Selenium
639
670
  when 'name'
640
671
  how = 'css selector'
641
672
  what = "*[name='#{escape_css(what.to_s)}']"
642
- when 'tag name'
643
- how = 'css selector'
644
673
  end
645
674
 
646
675
  if what.is_a?(Hash)
@@ -20,14 +20,12 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
-
24
23
  #
25
24
  # Specification of the desired and/or actual capabilities of the browser that the
26
25
  # server is being asked to create.
27
26
  #
28
27
 
29
28
  class Capabilities
30
-
31
29
  KNOWN = [
32
30
  :browser_name,
33
31
  :browser_version,
@@ -59,10 +57,25 @@ module Selenium
59
57
  # Backward compatibility
60
58
  #
61
59
 
62
- alias_method :version, :browser_version
63
- alias_method :version=, :browser_version=
64
- alias_method :platform, :platform_name
65
- alias_method :platform=, :platform_name=
60
+ def version
61
+ WebDriver.logger.deprecate('`Capabilities#version`', '`Capabilities#browser_version`', id: :jwp_caps)
62
+ browser_version
63
+ end
64
+
65
+ def version=(value)
66
+ WebDriver.logger.deprecate('`Capabilities#version=`', '`Capabilities#browser_version=`', id: :jwp_caps)
67
+ self.browser_version = value
68
+ end
69
+
70
+ def platform
71
+ WebDriver.logger.deprecate('`Capabilities#platform`', '`Capabilities#platform_name`', id: :jwp_caps)
72
+ platform_name
73
+ end
74
+
75
+ def platform=(value)
76
+ WebDriver.logger.deprecate('`Capabilities#platform=`', '`Capabilities#platform_name=`', id: :jwp_caps)
77
+ self.platform_name = value
78
+ end
66
79
 
67
80
  #
68
81
  # Convenience methods for the common choices.
@@ -70,44 +83,52 @@ module Selenium
70
83
 
71
84
  class << self
72
85
  def chrome(opts = {})
86
+ WebDriver.logger.deprecate('Remote::Capabilities.chrome', 'Options.chrome', id: :caps_browsers)
73
87
  new({
74
88
  browser_name: 'chrome'
75
89
  }.merge(opts))
76
90
  end
77
91
 
78
92
  def edge(opts = {})
93
+ WebDriver.logger.deprecate('Remote::Capabilities.edge', 'Options.edge', id: :caps_browsers)
79
94
  new({
80
95
  browser_name: 'MicrosoftEdge'
81
96
  }.merge(opts))
82
97
  end
83
- alias_method :microsoftedge, :edge
98
+ alias microsoftedge edge
84
99
 
85
100
  def firefox(opts = {})
101
+ WebDriver.logger.deprecate('Remote::Capabilities.firefox', 'Options.firefox', id: :caps_browsers)
86
102
  new({
87
103
  browser_name: 'firefox'
88
104
  }.merge(opts))
89
105
  end
90
- alias_method :ff, :firefox
106
+ alias ff firefox
91
107
 
92
108
  def safari(opts = {})
109
+ WebDriver.logger.deprecate('Remote::Capabilities.safari', 'Options.safari', id: :caps_browsers)
93
110
  new({
94
- browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
111
+ browser_name: Selenium::WebDriver::Safari.technology_preview? ? 'Safari Technology Preview' : 'safari'
95
112
  }.merge(opts))
96
113
  end
97
114
 
98
115
  def htmlunit(opts = {})
116
+ WebDriver.logger.deprecate('Remote::Capabilities.htmlunit',
117
+ 'as argument in constructor',
118
+ id: :caps_browsers)
99
119
  new({
100
120
  browser_name: 'htmlunit'
101
121
  }.merge(opts))
102
122
  end
103
123
 
104
124
  def internet_explorer(opts = {})
125
+ WebDriver.logger.deprecate('Remote::Capabilities.ie', 'Options.ie', id: :caps_browsers)
105
126
  new({
106
127
  browser_name: 'internet explorer',
107
128
  platform_name: :windows
108
129
  }.merge(opts))
109
130
  end
110
- alias_method :ie, :internet_explorer
131
+ alias ie internet_explorer
111
132
 
112
133
  def always_match(capabilities)
113
134
  new(always_match: capabilities)
@@ -134,7 +155,8 @@ module Selenium
134
155
 
135
156
  # Remote Server Specific
136
157
  if data.key?('webdriver.remote.sessionid')
137
- caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
158
+ caps[:remote_session_id] =
159
+ data.delete('webdriver.remote.sessionid')
138
160
  end
139
161
 
140
162
  KNOWN.each do |cap|
@@ -269,7 +291,7 @@ module Selenium
269
291
  as_json == other.as_json
270
292
  end
271
293
 
272
- alias_method :eql?, :==
294
+ alias eql? ==
273
295
 
274
296
  protected
275
297
 
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
-
24
23
  #
25
24
  # Driver implementation for remote server.
26
25
  # @api private
@@ -29,19 +28,13 @@ module Selenium
29
28
  class Driver < WebDriver::Driver
30
29
  include DriverExtensions::UploadsFiles
31
30
  include DriverExtensions::HasSessionId
32
- include DriverExtensions::HasRemoteStatus
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)
42
- end
43
- opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
44
- super
31
+
32
+ def initialize(capabilities: nil, options: nil, service: nil, url: nil, **opts)
33
+ raise ArgumentError, "Can not set :service object on #{self.class}" if service
34
+
35
+ url ||= "http://#{Platform.localhost}:4444/wd/hub"
36
+ caps = process_options(options, capabilities)
37
+ super(caps: caps, url: url, **opts)
45
38
  @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
46
39
  end
47
40
 
@@ -53,7 +46,13 @@ module Selenium
53
46
 
54
47
  def devtools_version
55
48
  capabilities['se:cdpVersion']&.split('.')&.first ||
56
- raise(Error::WebDriverError, "DevTools is not supported by the Remote Server")
49
+ raise(Error::WebDriverError, 'DevTools is not supported by the Remote Server')
50
+ end
51
+
52
+ def process_options(options, capabilities)
53
+ raise ArgumentError, "#{self.class} needs :options to be set" if options.nil? && capabilities.nil?
54
+
55
+ super(options, capabilities)
57
56
  end
58
57
  end # Driver
59
58
  end # Remote
@@ -22,7 +22,6 @@ require 'curb'
22
22
  module Selenium
23
23
  module WebDriver
24
24
  module Remote
25
-
26
25
  module Http
27
26
  #
28
27
  # An alternative to the default Net::HTTP client.
@@ -38,7 +37,6 @@ module Selenium
38
37
  #
39
38
 
40
39
  class Curb < Common
41
-
42
40
  def quit_errors
43
41
  [Curl::Err::RecvError] + super
44
42
  end
@@ -75,9 +75,10 @@ module Selenium
75
75
  begin
76
76
  request = new_request_for(verb, url, headers, payload)
77
77
  response = response_for(request)
78
- rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EADDRINUSE
79
- # a retry is sometimes needed on Windows XP where we may quickly
80
- # run out of ephemeral ports
78
+ rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EADDRINUSE, Errno::EADDRNOTAVAIL
79
+ # a retry is sometimes needed:
80
+ # on Windows XP where we may quickly run out of ephemeral ports
81
+ # when the port becomes temporarily unavailable
81
82
  #
82
83
  # A more robust solution is bumping the MaxUserPort setting
83
84
  # as described here:
@@ -85,13 +86,6 @@ module Selenium
85
86
  # http://msdn.microsoft.com/en-us/library/aa560610%28v=bts.20%29.aspx
86
87
  raise if retries >= MAX_RETRIES
87
88
 
88
- retries += 1
89
- sleep 2
90
- retry
91
- rescue Errno::EADDRNOTAVAIL => e
92
- # a retry is sometimes needed when the port becomes temporarily unavailable
93
- raise if retries >= MAX_RETRIES
94
-
95
89
  retries += 1
96
90
  sleep 2
97
91
  retry
@@ -106,6 +100,7 @@ module Selenium
106
100
 
107
101
  request(:get, URI.parse(response['Location']), DEFAULT_HEADERS.dup, nil, redirects + 1)
108
102
  else
103
+ WebDriver.logger.debug(" <<< #{response.instance_variable_get(:@header).inspect}")
109
104
  create_response response.code, response.body, response.content_type
110
105
  end
111
106
  end
@@ -142,8 +137,8 @@ module Selenium
142
137
 
143
138
  def proxy
144
139
  @proxy ||= begin
145
- proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
146
- no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
140
+ proxy = ENV.fetch('http_proxy', nil) || ENV.fetch('HTTP_PROXY', nil)
141
+ no_proxy = ENV.fetch('no_proxy', nil) || ENV.fetch('NO_PROXY', nil)
147
142
 
148
143
  if proxy
149
144
  proxy = "http://#{proxy}" unless proxy.start_with?('http://')