selenium-webdriver 4.2.1 → 4.15.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +252 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE +1 -1
  5. data/NOTICE +1 -1
  6. data/README.md +2 -2
  7. data/bin/linux/selenium-manager +0 -0
  8. data/bin/macos/selenium-manager +0 -0
  9. data/bin/windows/selenium-manager.exe +0 -0
  10. data/lib/selenium/server.rb +22 -30
  11. data/lib/selenium/webdriver/atoms/findElements.js +3 -4
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +0 -0
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
  15. data/lib/selenium/webdriver/atoms.rb +5 -3
  16. data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
  17. data/lib/selenium/webdriver/{common/driver_extensions/has_network_connection.rb → bidi/browsing_context_info.rb} +10 -12
  18. data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
  19. data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
  20. data/lib/selenium/webdriver/{common/driver_extensions/has_location.rb → bidi/log/filter_by.rb} +14 -11
  21. data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
  22. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
  23. data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
  24. data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
  25. data/lib/selenium/webdriver/bidi/session.rb +13 -0
  26. data/lib/selenium/webdriver/bidi.rb +3 -2
  27. data/lib/selenium/webdriver/chrome/driver.rb +9 -29
  28. data/lib/selenium/webdriver/chrome/features.rb +8 -71
  29. data/lib/selenium/webdriver/chrome/options.rb +3 -223
  30. data/lib/selenium/webdriver/chrome/profile.rb +3 -83
  31. data/lib/selenium/webdriver/chrome/service.rb +4 -19
  32. data/lib/selenium/webdriver/chrome.rb +0 -16
  33. data/lib/selenium/webdriver/chromium/driver.rb +60 -0
  34. data/lib/selenium/webdriver/chromium/features.rb +99 -0
  35. data/lib/selenium/webdriver/chromium/options.rb +243 -0
  36. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  37. data/lib/selenium/webdriver/chromium.rb +29 -0
  38. data/lib/selenium/webdriver/common/action_builder.rb +11 -58
  39. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  40. data/lib/selenium/webdriver/common/driver.rb +29 -79
  41. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  42. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
  43. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  44. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
  46. data/lib/selenium/webdriver/common/driver_extensions/has_bidi.rb +0 -2
  47. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +0 -1
  48. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
  49. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +0 -2
  50. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  51. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +65 -0
  53. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
  54. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +0 -1
  55. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
  56. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -69
  57. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
  58. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +0 -2
  59. data/lib/selenium/webdriver/common/driver_finder.rb +45 -0
  60. data/lib/selenium/webdriver/common/element.rb +7 -7
  61. data/lib/selenium/webdriver/common/error.rb +27 -4
  62. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  63. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +19 -36
  64. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +2 -2
  65. data/lib/selenium/webdriver/common/interactions/scroll.rb +7 -5
  66. data/lib/selenium/webdriver/common/local_driver.rb +46 -0
  67. data/lib/selenium/webdriver/common/logger.rb +90 -25
  68. data/lib/selenium/webdriver/common/manager.rb +0 -27
  69. data/lib/selenium/webdriver/common/options.rb +17 -17
  70. data/lib/selenium/webdriver/common/platform.rb +4 -50
  71. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  72. data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
  73. data/lib/selenium/webdriver/common/proxy.rb +2 -2
  74. data/lib/selenium/webdriver/common/selenium_manager.rb +134 -0
  75. data/lib/selenium/webdriver/common/service.rb +21 -30
  76. data/lib/selenium/webdriver/common/service_manager.rb +6 -12
  77. data/lib/selenium/webdriver/common/shadow_root.rb +1 -2
  78. data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
  79. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  80. data/lib/selenium/webdriver/common/takes_screenshot.rb +2 -3
  81. data/lib/selenium/webdriver/common/target_locator.rb +2 -3
  82. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  83. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  84. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  85. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  86. data/lib/selenium/webdriver/common/websocket_connection.rb +22 -7
  87. data/lib/selenium/webdriver/common/window.rb +6 -6
  88. data/lib/selenium/webdriver/common/zipper.rb +1 -1
  89. data/lib/selenium/webdriver/common.rb +8 -3
  90. data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
  91. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
  92. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
  93. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  94. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
  95. data/lib/selenium/webdriver/devtools/request.rb +0 -2
  96. data/lib/selenium/webdriver/devtools/response.rb +0 -2
  97. data/lib/selenium/webdriver/devtools.rb +12 -2
  98. data/lib/selenium/webdriver/edge/driver.rb +9 -3
  99. data/lib/selenium/webdriver/edge/features.rb +7 -4
  100. data/lib/selenium/webdriver/edge/options.rb +17 -5
  101. data/lib/selenium/webdriver/edge/profile.rb +2 -2
  102. data/lib/selenium/webdriver/edge/service.rb +8 -7
  103. data/lib/selenium/webdriver/edge.rb +0 -2
  104. data/lib/selenium/webdriver/firefox/driver.rb +8 -2
  105. data/lib/selenium/webdriver/firefox/features.rb +10 -3
  106. data/lib/selenium/webdriver/firefox/options.rb +4 -15
  107. data/lib/selenium/webdriver/firefox/profile.rb +7 -7
  108. data/lib/selenium/webdriver/firefox/service.rb +0 -18
  109. data/lib/selenium/webdriver/firefox.rb +0 -14
  110. data/lib/selenium/webdriver/ie/driver.rb +7 -1
  111. data/lib/selenium/webdriver/{common/driver_extensions/has_remote_status.rb → ie/features.rb} +10 -7
  112. data/lib/selenium/webdriver/ie/options.rb +4 -3
  113. data/lib/selenium/webdriver/ie/service.rb +0 -22
  114. data/lib/selenium/webdriver/ie.rb +4 -17
  115. data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +10 -4
  116. data/lib/selenium/webdriver/remote/bridge.rb +48 -39
  117. data/lib/selenium/webdriver/remote/capabilities.rb +3 -53
  118. data/lib/selenium/webdriver/remote/driver.rb +35 -14
  119. data/lib/selenium/webdriver/remote/features.rb +75 -0
  120. data/lib/selenium/webdriver/remote/http/common.rb +3 -3
  121. data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
  122. data/lib/selenium/webdriver/remote/http/default.rb +2 -2
  123. data/lib/selenium/webdriver/remote/response.rb +0 -1
  124. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  125. data/lib/selenium/webdriver/remote.rb +1 -1
  126. data/lib/selenium/webdriver/safari/driver.rb +7 -1
  127. data/lib/selenium/webdriver/safari/features.rb +5 -3
  128. data/lib/selenium/webdriver/safari/options.rb +5 -1
  129. data/lib/selenium/webdriver/safari/service.rb +10 -4
  130. data/lib/selenium/webdriver/safari.rb +1 -15
  131. data/lib/selenium/webdriver/support/color.rb +17 -17
  132. data/lib/selenium/webdriver/support/guards/guard.rb +6 -5
  133. data/lib/selenium/webdriver/support/guards/guard_condition.rb +0 -2
  134. data/lib/selenium/webdriver/support/guards.rb +1 -1
  135. data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
  136. data/lib/selenium/webdriver/support/select.rb +3 -1
  137. data/lib/selenium/webdriver/version.rb +1 -1
  138. data/lib/selenium/webdriver.rb +5 -4
  139. data/selenium-webdriver.gemspec +10 -11
  140. metadata +51 -90
  141. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
  142. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
  143. data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  module Firefox
23
23
  module Features
24
-
25
24
  FIREFOX_COMMANDS = {
26
25
  get_context: [:get, 'session/:session_id/moz/context'],
27
26
  set_context: [:post, 'session/:session_id/moz/context'],
@@ -30,12 +29,20 @@ module Selenium
30
29
  full_page_screenshot: [:get, 'session/:session_id/moz/screenshot/full']
31
30
  }.freeze
32
31
 
32
+ def command_list
33
+ FIREFOX_COMMANDS.merge(self.class::COMMANDS)
34
+ end
35
+
33
36
  def commands(command)
34
- FIREFOX_COMMANDS[command] || self.class::COMMANDS[command]
37
+ command_list[command]
35
38
  end
36
39
 
37
40
  def install_addon(path, temporary)
38
- addon = File.open(path, 'rb') { |crx_file| Base64.strict_encode64 crx_file.read }
41
+ addon = if File.directory?(path)
42
+ Zipper.zip(path)
43
+ else
44
+ File.open(path, 'rb') { |crx_file| Base64.strict_encode64 crx_file.read }
45
+ end
39
46
 
40
47
  payload = {addon: addon}
41
48
  payload[:temporary] = temporary unless temporary.nil?
@@ -45,7 +45,7 @@ module Selenium
45
45
  #
46
46
  # @example
47
47
  # options = Selenium::WebDriver::Firefox::Options.new(args: ['--host=127.0.0.1'])
48
- # driver = Selenium::WebDriver.for :firefox, capabilities: options
48
+ # driver = Selenium::WebDriver.for :firefox, options: options
49
49
  #
50
50
  # @param [Hash] opts the pre-defined options to create the Firefox::Options with
51
51
  # @option opts [String] :binary Path to the Firefox executable to use
@@ -57,7 +57,8 @@ module Selenium
57
57
  #
58
58
 
59
59
  def initialize(log_level: nil, **opts)
60
- @debugger_address = opts.delete(:debugger_address)
60
+ @debugger_address = opts.delete(:debugger_address) { true }
61
+ opts[:accept_insecure_certs] = true unless opts.key?(:accept_insecure_certs)
61
62
 
62
63
  super(**opts)
63
64
 
@@ -98,18 +99,6 @@ module Selenium
98
99
  @options[:prefs][name] = value
99
100
  end
100
101
 
101
- #
102
- # Run Firefox in headless mode.
103
- #
104
- # @example Enable headless mode
105
- # options = Selenium::WebDriver::Firefox::Options.new
106
- # options.headless!
107
- #
108
-
109
- def headless!
110
- add_argument '-headless'
111
- end
112
-
113
102
  #
114
103
  # Sets Firefox profile.
115
104
  #
@@ -177,7 +166,7 @@ module Selenium
177
166
  end
178
167
 
179
168
  def camelize?(key)
180
- key != "prefs"
169
+ key != 'prefs'
181
170
  end
182
171
  end # Options
183
172
  end # Firefox
@@ -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
@@ -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
 
@@ -160,7 +160,7 @@ module Selenium
160
160
  destination = File.join(directory, 'extensions')
161
161
 
162
162
  @extensions.each do |name, extension|
163
- WebDriver.logger.debug({extenstion: name}.inspect)
163
+ WebDriver.logger.debug({extension: name}.inspect, id: :firefox_profile)
164
164
  extension.write_to(destination)
165
165
  end
166
166
  end
@@ -23,25 +23,7 @@ module Selenium
23
23
  class Service < WebDriver::Service
24
24
  DEFAULT_PORT = 4444
25
25
  EXECUTABLE = 'geckodriver'
26
- MISSING_TEXT = <<~ERROR
27
- Unable to find Mozilla geckodriver. Please download the server from
28
- https://github.com/mozilla/geckodriver/releases and place it somewhere on your PATH.
29
- More info at https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/WebDriver.
30
- ERROR
31
26
  SHUTDOWN_SUPPORTED = false
32
-
33
- private
34
-
35
- # NOTE: This processing is deprecated
36
- def extract_service_args(driver_opts)
37
- driver_args = super
38
- driver_opts = driver_opts.dup
39
- driver_args << "--binary=#{driver_opts[:binary]}" if driver_opts.key?(:binary)
40
- driver_args << "--log=#{driver_opts[:log]}" if driver_opts.key?(:log)
41
- driver_args << "--marionette-port=#{driver_opts[:marionette_port]}" if driver_opts.key?(:marionette_port)
42
- driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key?(:host)
43
- driver_args
44
- end
45
27
  end # Service
46
28
  end # Firefox
47
29
  end # WebDriver
@@ -42,20 +42,6 @@ module Selenium
42
42
  # until WebDriver Bidi is available.
43
43
  DEVTOOLS_VERSION = 85
44
44
 
45
- def self.driver_path=(path)
46
- WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path=',
47
- 'Selenium::WebDriver::Firefox::Service#driver_path=',
48
- id: :driver_path
49
- Selenium::WebDriver::Firefox::Service.driver_path = path
50
- end
51
-
52
- def self.driver_path
53
- WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path',
54
- 'Selenium::WebDriver::Firefox::Service#driver_path',
55
- id: :driver_path
56
- Selenium::WebDriver::Firefox::Service.driver_path
57
- end
58
-
59
45
  def self.path=(path)
60
46
  Platform.assert_executable path
61
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,6 +29,13 @@ module Selenium
30
29
  class Driver < WebDriver::Driver
31
30
  EXTENSIONS = [DriverExtensions::HasWebStorage].freeze
32
31
 
32
+ include LocalDriver
33
+
34
+ def initialize(options: nil, service: nil, url: nil, **opts)
35
+ caps, url = initialize_local_driver(options, service, url)
36
+ super(caps: caps, url: url, **opts)
37
+ end
38
+
33
39
  def browser
34
40
  :internet_explorer
35
41
  end
@@ -19,13 +19,16 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- module DriverExtensions
23
- module HasRemoteStatus
24
- def remote_status
25
- WebDriver.logger.deprecate('#remote_status', '#status')
26
- @bridge.status
22
+ module IE
23
+ module Features
24
+ def command_list
25
+ self.class::COMMANDS
27
26
  end
28
- end # HasRemoteStatus
29
- end # DriverExtensions
27
+
28
+ def commands(command)
29
+ command_list[command]
30
+ end
31
+ end # Bridge
32
+ end # Ie
30
33
  end # WebDriver
31
34
  end # Selenium
@@ -41,7 +41,8 @@ module Selenium
41
41
  use_per_process_proxy: 'ie.usePerProcessProxy',
42
42
  use_legacy_file_upload_dialog_handling: 'ie.useLegacyFileUploadDialogHandling',
43
43
  attach_to_edge_chrome: 'ie.edgechromium',
44
- edge_executable_path: 'ie.edgepath'
44
+ edge_executable_path: 'ie.edgepath',
45
+ ignore_process_match: 'ie.ignoreprocessmatch'
45
46
  }.freeze
46
47
  BROWSER = 'internet explorer'
47
48
 
@@ -52,12 +53,12 @@ module Selenium
52
53
  #
53
54
  # @example
54
55
  # options = Selenium::WebDriver::IE::Options.new(args: ['--host=127.0.0.1'])
55
- # driver = Selenium::WebDriver.for(:ie, capabilities: options)
56
+ # driver = Selenium::WebDriver.for(:ie, options: options)
56
57
  #
57
58
  # @example
58
59
  # options = Selenium::WebDriver::IE::Options.new
59
60
  # options.element_scroll_behavior = Selenium::WebDriver::IE::Options::SCROLL_BOTTOM
60
- # driver = Selenium::WebDriver.for(:ie, capabilities: options)
61
+ # driver = Selenium::WebDriver.for(:ie, options: options)
61
62
  #
62
63
  # @param [Hash] opts the pre-defined options
63
64
  # @option opts [Array<String>] args
@@ -23,29 +23,7 @@ module Selenium
23
23
  class Service < WebDriver::Service
24
24
  DEFAULT_PORT = 5555
25
25
  EXECUTABLE = 'IEDriverServer'
26
- MISSING_TEXT = <<~ERROR
27
- Unable to find IEDriverServer. Please download the server from
28
- https://www.selenium.dev/downloads/ and place it somewhere on your PATH.
29
- More info at https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver.
30
- ERROR
31
26
  SHUTDOWN_SUPPORTED = true
32
-
33
- private
34
-
35
- # NOTE: This processing is deprecated
36
- def extract_service_args(driver_opts)
37
- driver_args = super
38
- driver_opts = driver_opts.dup
39
- driver_args << "--log-level=#{driver_opts[:log_level].to_s.upcase}" if driver_opts.key?(:log_level)
40
- driver_args << "--log-file=#{driver_opts[:log_file]}" if driver_opts.key?(:log_file)
41
- if driver_opts.key?(:implementation)
42
- driver_args << "--implementation=#{driver_opts[:implementation].to_s.upcase}"
43
- end
44
- driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key?(:host)
45
- driver_args << "--extract_path=#{driver_opts[:extract_path]}" if driver_opts.key?(:extract_path)
46
- driver_args << "--silent" if driver_opts[:silent] == true
47
- driver_args
48
- end
49
27
  end # Server
50
28
  end # IE
51
29
  end # WebDriver
@@ -20,23 +20,10 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module IE
23
- autoload :Driver, 'selenium/webdriver/ie/driver'
24
- autoload :Options, 'selenium/webdriver/ie/options'
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
23
+ autoload :Features, 'selenium/webdriver/ie/features'
24
+ autoload :Driver, 'selenium/webdriver/ie/driver'
25
+ autoload :Options, 'selenium/webdriver/ie/options'
26
+ autoload :Service, 'selenium/webdriver/ie/service'
40
27
  end # IE
41
28
  end # WebDriver
42
29
  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
@@ -146,12 +145,19 @@ module Selenium
146
145
  take_element_screenshot: [:get, 'session/:session_id/element/:id/screenshot'],
147
146
 
148
147
  #
149
- # server extensions
148
+ # virtual-authenticator
150
149
  #
151
150
 
152
- upload_file: [:post, 'session/:session_id/se/file']
153
- }.freeze
151
+ add_virtual_authenticator: [:post, 'session/:session_id/webauthn/authenticator'],
152
+ remove_virtual_authenticator: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId'],
153
+ add_credential: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/credential'],
154
+ get_credentials: [:get, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'],
155
+ remove_credential: [:delete,
156
+ 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials/:credentialId'],
157
+ remove_all_credentials: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'],
158
+ set_user_verified: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/uv']
154
159
 
160
+ }.freeze
155
161
  end # Bridge
156
162
  end # Remote
157
163
  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
@@ -186,6 +187,7 @@ module Selenium
186
187
  execute :delete_session
187
188
  http.close
188
189
  rescue *QUIT_ERRORS
190
+ nil
189
191
  end
190
192
 
191
193
  def close
@@ -367,18 +369,10 @@ module Selenium
367
369
  # actions
368
370
  #
369
371
 
370
- def action(deprecated_async = nil, async: false, devices: [], duration: 250)
371
- ActionBuilder.new self, nil, nil, deprecated_async, async: async, devices: devices, duration: duration
372
- end
373
- alias_method :actions, :action
374
-
375
- def mouse
376
- raise Error::UnsupportedOperationError, '#mouse is no longer supported, use #action instead'
377
- end
378
-
379
- def keyboard
380
- 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
381
374
  end
375
+ alias actions action
382
376
 
383
377
  def send_actions(data)
384
378
  execute :actions, {}, {actions: data}
@@ -397,37 +391,19 @@ module Selenium
397
391
  end
398
392
 
399
393
  def send_keys_to_element(element, keys)
400
- # TODO: rework file detectors before Selenium 4.0
401
- if @file_detector
402
- local_files = keys.first&.split("\n")&.map { |key| @file_detector.call(Array(key)) }&.compact
403
- if local_files.any?
404
- keys = local_files.map { |local_file| upload(local_file) }
405
- keys = Array(keys.join("\n"))
406
- end
407
- end
408
-
409
- # Keep .split(//) for backward compatibility for now
394
+ keys = upload_if_necessary(keys) if @file_detector
410
395
  text = keys.join
411
396
  execute :element_send_keys, {id: element}, {value: text.chars, text: text}
412
397
  end
413
398
 
414
- def upload(local_file)
415
- unless File.file?(local_file)
416
- WebDriver.logger.debug("File detector only works with files. #{local_file.inspect} isn`t a file!")
417
- raise Error::WebDriverError, "You are trying to work with something that isn't a file."
418
- end
419
-
420
- execute :upload_file, {}, {file: Zipper.zip_file(local_file)}
421
- end
422
-
423
399
  def clear_element(element)
424
400
  execute :element_clear, id: element
425
401
  end
426
402
 
427
403
  def submit_element(element)
428
- script = "var form = arguments[0];\n" \
429
- "while (form.nodeName != \"FORM\" && form.parentNode) {\n" \
430
- " form = form.parentNode;\n" \
404
+ script = "/* submitForm */ var form = arguments[0];\n" \
405
+ "while (form.nodeName != \"FORM\" && form.parentNode) {\n " \
406
+ "form = form.parentNode;\n" \
431
407
  "}\n" \
432
408
  "if (!form) { throw Error('Unable to find containing form element'); }\n" \
433
409
  "if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" \
@@ -437,7 +413,7 @@ module Selenium
437
413
 
438
414
  execute_script(script, Element::ELEMENT_KEY => element)
439
415
  rescue Error::JavascriptError
440
- raise Error::UnsupportedOperationError, "To submit an element, it must be nested inside a form element"
416
+ raise Error::UnsupportedOperationError, 'To submit an element, it must be nested inside a form element'
441
417
  end
442
418
 
443
419
  #
@@ -449,7 +425,7 @@ module Selenium
449
425
  end
450
426
 
451
427
  def element_attribute(element, name)
452
- WebDriver.logger.info "Using script for :getAttribute of #{name}"
428
+ WebDriver.logger.debug "Using script for :getAttribute of #{name}", id: :script
453
429
  execute_atom :getAttribute, element, name
454
430
  end
455
431
 
@@ -509,7 +485,7 @@ module Selenium
509
485
  end
510
486
 
511
487
  def element_displayed?(element)
512
- WebDriver.logger.info 'Using script for :isDisplayed'
488
+ WebDriver.logger.debug 'Using script for :isDisplayed', id: :script
513
489
  execute_atom :isDisplayed, element
514
490
  end
515
491
 
@@ -525,7 +501,7 @@ module Selenium
525
501
  Element.new self, element_id_from(execute(:get_active_element))
526
502
  end
527
503
 
528
- alias_method :switch_to_active_element, :active_element
504
+ alias switch_to_active_element active_element
529
505
 
530
506
  def find_element_by(how, what, parent_ref = [])
531
507
  how, what = convert_locator(how, what)
@@ -568,6 +544,39 @@ module Selenium
568
544
  ShadowRoot.new self, shadow_root_id_from(id)
569
545
  end
570
546
 
547
+ #
548
+ # virtual-authenticator
549
+ #
550
+
551
+ def add_virtual_authenticator(options)
552
+ authenticator_id = execute :add_virtual_authenticator, {}, options.as_json
553
+ VirtualAuthenticator.new(self, authenticator_id, options)
554
+ end
555
+
556
+ def remove_virtual_authenticator(id)
557
+ execute :remove_virtual_authenticator, {authenticatorId: id}
558
+ end
559
+
560
+ def add_credential(credential, id)
561
+ execute :add_credential, {authenticatorId: id}, credential
562
+ end
563
+
564
+ def credentials(authenticator_id)
565
+ execute :get_credentials, {authenticatorId: authenticator_id}
566
+ end
567
+
568
+ def remove_credential(credential_id, authenticator_id)
569
+ execute :remove_credential, {credentialId: credential_id, authenticatorId: authenticator_id}
570
+ end
571
+
572
+ def remove_all_credentials(authenticator_id)
573
+ execute :remove_all_credentials, {authenticatorId: authenticator_id}
574
+ end
575
+
576
+ def user_verified(verified, authenticator_id)
577
+ execute :set_user_verified, {authenticatorId: authenticator_id}, {isUserVerified: verified}
578
+ end
579
+
571
580
  private
572
581
 
573
582
  #
@@ -588,7 +597,7 @@ module Selenium
588
597
  raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
589
598
  end
590
599
 
591
- WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
600
+ WebDriver.logger.debug("-> #{verb.to_s.upcase} #{path}", id: :command)
592
601
  http.call(verb, path, command_hash)['value']
593
602
  end
594
603
 
@@ -655,7 +664,7 @@ module Selenium
655
664
  [how, what]
656
665
  end
657
666
 
658
- ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/.freeze
667
+ ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/
659
668
  UNICODE_CODE_POINT = 30
660
669
 
661
670
  # Escapes invalid characters in CSS selector.
@@ -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,
@@ -55,60 +53,11 @@ module Selenium
55
53
  end
56
54
  end
57
55
 
58
- #
59
- # Backward compatibility
60
- #
61
-
62
- alias_method :version, :browser_version
63
- alias_method :version=, :browser_version=
64
- alias_method :platform, :platform_name
65
- alias_method :platform=, :platform_name=
66
-
67
56
  #
68
57
  # Convenience methods for the common choices.
69
58
  #
70
59
 
71
60
  class << self
72
- def chrome(opts = {})
73
- new({
74
- browser_name: 'chrome'
75
- }.merge(opts))
76
- end
77
-
78
- def edge(opts = {})
79
- new({
80
- browser_name: 'MicrosoftEdge'
81
- }.merge(opts))
82
- end
83
- alias_method :microsoftedge, :edge
84
-
85
- def firefox(opts = {})
86
- new({
87
- browser_name: 'firefox'
88
- }.merge(opts))
89
- end
90
- alias_method :ff, :firefox
91
-
92
- def safari(opts = {})
93
- new({
94
- browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
95
- }.merge(opts))
96
- end
97
-
98
- def htmlunit(opts = {})
99
- new({
100
- browser_name: 'htmlunit'
101
- }.merge(opts))
102
- end
103
-
104
- def internet_explorer(opts = {})
105
- new({
106
- browser_name: 'internet explorer',
107
- platform_name: :windows
108
- }.merge(opts))
109
- end
110
- alias_method :ie, :internet_explorer
111
-
112
61
  def always_match(capabilities)
113
62
  new(always_match: capabilities)
114
63
  end
@@ -134,7 +83,8 @@ module Selenium
134
83
 
135
84
  # Remote Server Specific
136
85
  if data.key?('webdriver.remote.sessionid')
137
- caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
86
+ caps[:remote_session_id] =
87
+ data.delete('webdriver.remote.sessionid')
138
88
  end
139
89
 
140
90
  KNOWN.each do |cap|
@@ -269,7 +219,7 @@ module Selenium
269
219
  as_json == other.as_json
270
220
  end
271
221
 
272
- alias_method :eql?, :==
222
+ alias eql? ==
273
223
 
274
224
  protected
275
225
 
@@ -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,20 +28,18 @@ module Selenium
29
28
  class Driver < WebDriver::Driver
30
29
  include DriverExtensions::UploadsFiles
31
30
  include DriverExtensions::HasSessionId
32
- include DriverExtensions::HasRemoteStatus
31
+ include DriverExtensions::HasFileDownloads
33
32
 
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
33
+ def initialize(capabilities: nil, options: nil, service: nil, url: nil, **opts)
34
+ raise ArgumentError, "Can not set :service object on #{self.class}" if service
40
35
 
41
- opts[:desired_capabilities] = Remote::Capabilities.__send__(desired_capabilities)
42
- end
43
- opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
44
- super
36
+ url ||= "http://#{Platform.localhost}:4444/wd/hub"
37
+ caps = process_options(options, capabilities)
38
+ super(caps: caps, url: url, **opts)
45
39
  @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
40
+ command_list = @bridge.command_list
41
+ @bridge.extend(WebDriver::Remote::Features)
42
+ @bridge.add_commands(command_list)
46
43
  end
47
44
 
48
45
  private
@@ -52,8 +49,32 @@ module Selenium
52
49
  end
53
50
 
54
51
  def devtools_version
55
- capabilities['se:cdpVersion']&.split('.')&.first ||
56
- raise(Error::WebDriverError, "DevTools is not supported by the Remote Server")
52
+ cdp_version = capabilities['se:cdpVersion']&.split('.')&.first
53
+ raise Error::WebDriverError, 'DevTools is not supported by the Remote Server' unless cdp_version
54
+
55
+ Integer(cdp_version)
56
+ end
57
+
58
+ def process_options(options, capabilities)
59
+ if options && capabilities
60
+ msg = "Don't use both :options and :capabilities when initializing #{self.class}, prefer :options"
61
+ raise ArgumentError, msg
62
+ elsif options.nil? && capabilities.nil?
63
+ raise ArgumentError, "#{self.class} needs :options to be set"
64
+ end
65
+ options ? options.as_json : generate_capabilities(capabilities)
66
+ end
67
+
68
+ def generate_capabilities(capabilities)
69
+ Array(capabilities).map { |cap|
70
+ if cap.is_a? Symbol
71
+ cap = WebDriver::Options.send(cap)
72
+ elsif !cap.respond_to? :as_json
73
+ msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
74
+ raise ArgumentError, msg
75
+ end
76
+ cap.as_json
77
+ }.inject(:merge)
57
78
  end
58
79
  end # Driver
59
80
  end # Remote