selenium-webdriver 4.1.0 → 4.9.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 (157) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +234 -1
  3. data/Gemfile +2 -0
  4. data/LICENSE +1 -1
  5. data/NOTICE +1 -1
  6. data/README.md +1 -1
  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 +36 -27
  11. data/lib/selenium/webdriver/atoms/findElements.js +0 -0
  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 +2 -3
  16. data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
  17. data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
  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/bidi/log/filter_by.rb +40 -0
  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 +51 -0
  26. data/lib/selenium/webdriver/bidi.rb +56 -0
  27. data/lib/selenium/webdriver/chrome/driver.rb +9 -29
  28. data/lib/selenium/webdriver/chrome/features.rb +6 -68
  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 +3 -23
  32. data/lib/selenium/webdriver/chrome.rb +0 -14
  33. data/lib/selenium/webdriver/chromium/driver.rb +61 -0
  34. data/lib/selenium/webdriver/chromium/features.rb +103 -0
  35. data/lib/selenium/webdriver/chromium/options.rb +261 -0
  36. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  37. data/lib/selenium/webdriver/chromium/service.rb +42 -0
  38. data/lib/selenium/webdriver/chromium.rb +32 -0
  39. data/lib/selenium/webdriver/common/action_builder.rb +64 -22
  40. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  41. data/lib/selenium/webdriver/common/driver.rb +36 -74
  42. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  43. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
  44. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
  46. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
  47. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +10 -5
  48. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -1
  49. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
  50. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -4
  51. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
  53. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
  54. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +1 -2
  55. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -2
  56. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
  57. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -69
  58. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
  59. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -3
  60. data/lib/selenium/webdriver/common/driver_finder.rb +44 -0
  61. data/lib/selenium/webdriver/common/element.rb +8 -8
  62. data/lib/selenium/webdriver/common/error.rb +1 -3
  63. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  64. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  65. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
  66. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  67. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
  68. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  69. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  70. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  71. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
  72. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  73. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  74. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  75. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  76. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  77. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  78. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  79. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  80. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  81. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
  82. data/lib/selenium/webdriver/common/keys.rb +1 -0
  83. data/lib/selenium/webdriver/common/local_driver.rb +55 -0
  84. data/lib/selenium/webdriver/common/logger.rb +76 -24
  85. data/lib/selenium/webdriver/common/manager.rb +0 -27
  86. data/lib/selenium/webdriver/common/options.rb +32 -17
  87. data/lib/selenium/webdriver/common/platform.rb +8 -5
  88. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  89. data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
  90. data/lib/selenium/webdriver/common/proxy.rb +1 -1
  91. data/lib/selenium/webdriver/common/search_context.rb +0 -6
  92. data/lib/selenium/webdriver/common/selenium_manager.rb +108 -0
  93. data/lib/selenium/webdriver/common/service.rb +20 -23
  94. data/lib/selenium/webdriver/common/service_manager.rb +8 -15
  95. data/lib/selenium/webdriver/common/shadow_root.rb +2 -3
  96. data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
  97. data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
  98. data/lib/selenium/webdriver/common/takes_screenshot.rb +2 -3
  99. data/lib/selenium/webdriver/common/target_locator.rb +2 -3
  100. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  101. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  102. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  103. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  104. data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
  105. data/lib/selenium/webdriver/common/window.rb +6 -6
  106. data/lib/selenium/webdriver/common/zipper.rb +1 -1
  107. data/lib/selenium/webdriver/common.rb +21 -3
  108. data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
  109. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
  110. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
  111. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  112. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
  113. data/lib/selenium/webdriver/devtools/request.rb +1 -3
  114. data/lib/selenium/webdriver/devtools/response.rb +1 -3
  115. data/lib/selenium/webdriver/devtools.rb +17 -114
  116. data/lib/selenium/webdriver/edge/driver.rb +9 -3
  117. data/lib/selenium/webdriver/edge/features.rb +4 -4
  118. data/lib/selenium/webdriver/edge/options.rb +3 -5
  119. data/lib/selenium/webdriver/edge/profile.rb +2 -2
  120. data/lib/selenium/webdriver/edge/service.rb +2 -6
  121. data/lib/selenium/webdriver/firefox/driver.rb +9 -2
  122. data/lib/selenium/webdriver/firefox/features.rb +6 -6
  123. data/lib/selenium/webdriver/firefox/options.rb +9 -3
  124. data/lib/selenium/webdriver/firefox/profile.rb +8 -12
  125. data/lib/selenium/webdriver/firefox/service.rb +0 -6
  126. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  127. data/lib/selenium/webdriver/firefox.rb +1 -14
  128. data/lib/selenium/webdriver/ie/driver.rb +7 -1
  129. data/lib/selenium/webdriver/ie/service.rb +1 -7
  130. data/lib/selenium/webdriver/ie.rb +0 -14
  131. data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +15 -8
  132. data/lib/selenium/webdriver/remote/bridge.rb +65 -35
  133. data/lib/selenium/webdriver/remote/capabilities.rb +34 -12
  134. data/lib/selenium/webdriver/remote/driver.rb +19 -14
  135. data/lib/selenium/webdriver/remote/http/common.rb +3 -3
  136. data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
  137. data/lib/selenium/webdriver/remote/http/default.rb +7 -12
  138. data/lib/selenium/webdriver/remote/response.rb +2 -3
  139. data/lib/selenium/webdriver/remote.rb +0 -1
  140. data/lib/selenium/webdriver/safari/driver.rb +7 -1
  141. data/lib/selenium/webdriver/safari/features.rb +0 -2
  142. data/lib/selenium/webdriver/safari/options.rb +5 -1
  143. data/lib/selenium/webdriver/safari/service.rb +0 -4
  144. data/lib/selenium/webdriver/safari.rb +1 -15
  145. data/lib/selenium/webdriver/support/color.rb +22 -22
  146. data/lib/selenium/webdriver/support/guards/guard.rb +0 -2
  147. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -3
  148. data/lib/selenium/webdriver/support/guards.rb +1 -1
  149. data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
  150. data/lib/selenium/webdriver/support/select.rb +3 -1
  151. data/lib/selenium/webdriver/version.rb +1 -1
  152. data/lib/selenium/webdriver.rb +5 -4
  153. data/selenium-webdriver.gemspec +13 -12
  154. metadata +70 -73
  155. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
  156. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
  157. data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
@@ -61,9 +61,6 @@ module Selenium
61
61
  raise ArgumentError, "cannot find element by #{how.inspect}" unless by
62
62
 
63
63
  bridge.find_element_by by, what, ref
64
- rescue Selenium::WebDriver::Error::TimeoutError
65
- # Implicit Wait times out in Edge
66
- raise Selenium::WebDriver::Error::NoSuchElementError
67
64
  end
68
65
 
69
66
  #
@@ -79,9 +76,6 @@ module Selenium
79
76
  raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
80
77
 
81
78
  bridge.find_elements_by by, what, ref
82
- rescue Selenium::WebDriver::Error::TimeoutError
83
- # Implicit Wait times out in Edge
84
- []
85
79
  end
86
80
 
87
81
  private
@@ -0,0 +1,108 @@
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
+ require 'open3'
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ #
25
+ # Wrapper for getting information from the Selenium Manager binaries.
26
+ # This implementation is still in beta, and may change.
27
+ # @api private
28
+ #
29
+ class SeleniumManager
30
+ BIN_PATH = '../../../../../bin'
31
+
32
+ class << self
33
+ # @param [Options] options browser options.
34
+ # @return [String] the path to the correct driver.
35
+ def driver_path(options)
36
+ message = 'applicable driver not found; attempting to install with Selenium Manager (Beta)'
37
+ WebDriver.logger.info(message, id: :selenium_manager)
38
+
39
+ unless options.is_a?(Options)
40
+ raise ArgumentError, "SeleniumManager requires a WebDriver::Options instance, not #{options.inspect}"
41
+ end
42
+
43
+ command = [binary, '--browser', options.browser_name, '--output', 'json']
44
+ if options.browser_version
45
+ command << '--browser-version'
46
+ command << options.browser_version
47
+ end
48
+ if options.respond_to?(:binary) && !options.binary.nil?
49
+ command << '--browser-path'
50
+ command << options.binary.gsub('\\', '\\\\\\')
51
+ end
52
+ command << '--debug' if WebDriver.logger.debug?
53
+
54
+ location = run(*command)
55
+ WebDriver.logger.debug("Driver found at #{location}", id: :selenium_manager)
56
+ Platform.assert_executable location
57
+
58
+ location
59
+ end
60
+
61
+ private
62
+
63
+ # @return [String] the path to the correct selenium manager
64
+ def binary
65
+ @binary ||= begin
66
+ path = File.expand_path(BIN_PATH, __FILE__)
67
+ path << if Platform.windows?
68
+ '/windows/selenium-manager.exe'
69
+ elsif Platform.mac?
70
+ '/macos/selenium-manager'
71
+ elsif Platform.linux?
72
+ '/linux/selenium-manager'
73
+ end
74
+ location = File.expand_path(path, __FILE__)
75
+ unless location.is_a?(String) && File.exist?(location) && File.executable?(location)
76
+ raise Error::WebDriverError, 'Unable to obtain Selenium Manager'
77
+ end
78
+
79
+ WebDriver.logger.debug("Selenium Manager found at #{location}", id: :selenium_manager)
80
+ location
81
+ end
82
+ end
83
+
84
+ def run(*command)
85
+ WebDriver.logger.debug("Executing Process #{command}", id: :selenium_manager)
86
+
87
+ begin
88
+ stdout, stderr, status = Open3.capture3(*command)
89
+ json_output = stdout.empty? ? nil : JSON.parse(stdout)
90
+ result = json_output&.dig('result', 'message')
91
+ rescue StandardError => e
92
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}", e.message
93
+ end
94
+
95
+ if status.exitstatus.positive?
96
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{result}#{stderr}"
97
+ end
98
+
99
+ json_output['logs'].each do |log|
100
+ WebDriver.logger.send(log['level'].downcase, log['message'], id: :selenium_manager)
101
+ end
102
+
103
+ result
104
+ end
105
+ end
106
+ end # SeleniumManager
107
+ end # WebDriver
108
+ end # Selenium
@@ -39,12 +39,13 @@ module Selenium
39
39
  def ie(**opts)
40
40
  IE::Service.new(**opts)
41
41
  end
42
- alias_method :internet_explorer, :ie
42
+ alias internet_explorer ie
43
43
 
44
44
  def edge(**opts)
45
45
  Edge::Service.new(**opts)
46
46
  end
47
- alias_method :microsoftedge, :edge
47
+ alias microsoftedge edge
48
+ alias msedge edge
48
49
 
49
50
  def safari(**opts)
50
51
  Safari::Service.new(**opts)
@@ -56,8 +57,8 @@ module Selenium
56
57
  end
57
58
  end
58
59
 
59
- attr_accessor :host
60
- attr_reader :executable_path, :port, :extra_args
60
+ attr_accessor :host, :executable_path, :port, :log, :args
61
+ alias extra_args args
61
62
 
62
63
  #
63
64
  # End users should use a class method for the desired driver, rather than using this directly.
@@ -65,24 +66,29 @@ module Selenium
65
66
  # @api private
66
67
  #
67
68
 
68
- def initialize(path: nil, port: nil, args: nil)
69
- path ||= self.class.driver_path
69
+ def initialize(path: nil, port: nil, log: nil, args: nil)
70
70
  port ||= self.class::DEFAULT_PORT
71
71
  args ||= []
72
72
 
73
- @executable_path = binary_path(path)
73
+ @executable_path = path
74
74
  @host = Platform.localhost
75
75
  @port = Integer(port)
76
+ @log = case log
77
+ when :stdout
78
+ $stdout
79
+ when :stderr
80
+ $stderr
81
+ else
82
+ log
83
+ end
76
84
 
77
- @extra_args = args.is_a?(Hash) ? extract_service_args(args) : args
85
+ @args = args.is_a?(Hash) ? extract_service_args(args) : args
78
86
 
79
87
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
80
88
  end
81
89
 
82
90
  def launch
83
- sm = ServiceManager.new(self)
84
- sm.start
85
- sm
91
+ ServiceManager.new(self).tap(&:start)
86
92
  end
87
93
 
88
94
  def shutdown_supported
@@ -92,20 +98,11 @@ module Selenium
92
98
  protected
93
99
 
94
100
  def extract_service_args(driver_opts)
101
+ WebDriver.logger.deprecate('initializing Service class with :args using Hash',
102
+ ':args parameter with an Array of String values',
103
+ id: :driver_opts)
95
104
  driver_opts.key?(:args) ? driver_opts.delete(:args) : []
96
105
  end
97
-
98
- private
99
-
100
- def binary_path(path = nil)
101
- path = path.call if path.is_a?(Proc)
102
- path ||= Platform.find_binary(self.class::EXECUTABLE)
103
-
104
- raise Error::WebDriverError, self.class::MISSING_TEXT unless path
105
-
106
- Platform.assert_executable path
107
- path
108
- end
109
106
  end # Service
110
107
  end # WebDriver
111
108
  end # Selenium
@@ -40,7 +40,8 @@ module Selenium
40
40
  @executable_path = config.executable_path
41
41
  @host = Platform.localhost
42
42
  @port = config.port
43
- @extra_args = config.extra_args
43
+ @extra_args = config.args
44
+ @io = config.log
44
45
  @shutdown_supported = config.shutdown_supported
45
46
 
46
47
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
@@ -49,7 +50,7 @@ module Selenium
49
50
  def start
50
51
  raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
51
52
 
52
- Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
53
+ Platform.exit_hook { stop } # make sure we don't leave the server running
53
54
 
54
55
  socket_lock.locked do
55
56
  find_free_port
@@ -60,10 +61,11 @@ module Selenium
60
61
 
61
62
  def stop
62
63
  return unless @shutdown_supported
64
+ return if process_exited?
63
65
 
64
66
  stop_server
65
67
  @process.poll_for_exit STOP_TIMEOUT
66
- rescue ChildProcess::TimeoutError
68
+ rescue ChildProcess::TimeoutError, Errno::ECONNREFUSED
67
69
  nil # noop
68
70
  ensure
69
71
  stop_process
@@ -76,14 +78,10 @@ module Selenium
76
78
  private
77
79
 
78
80
  def build_process(*command)
79
- WebDriver.logger.debug("Executing Process #{command}")
81
+ WebDriver.logger.debug("Executing Process #{command}", id: :driver_service)
80
82
  @process = ChildProcess.build(*command)
81
- if WebDriver.logger.debug?
82
- @process.io.stdout = @process.io.stderr = WebDriver.logger.io
83
- elsif Platform.jruby?
84
- # Apparently we need to read the output of drivers on JRuby.
85
- @process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
86
- end
83
+ @io ||= WebDriver.logger.io if WebDriver.logger.debug?
84
+ @process.io = @io if @io
87
85
 
88
86
  @process
89
87
  end
@@ -103,8 +101,6 @@ module Selenium
103
101
 
104
102
  def start_process
105
103
  @process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
106
- # NOTE: this is a bug only in Windows 7
107
- @process.leader = true unless Platform.windows?
108
104
  @process.start
109
105
  end
110
106
 
@@ -112,12 +108,9 @@ module Selenium
112
108
  return if process_exited?
113
109
 
114
110
  @process.stop STOP_TIMEOUT
115
- @process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
116
111
  end
117
112
 
118
113
  def stop_server
119
- return if process_exited?
120
-
121
114
  connect_to_server do |http|
122
115
  headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
123
116
  http.get('/shutdown', headers)
@@ -42,10 +42,10 @@ module Selenium
42
42
  def ==(other)
43
43
  other.is_a?(self.class) && ref == other.ref
44
44
  end
45
- alias_method :eql?, :==
45
+ alias eql? ==
46
46
 
47
47
  def hash
48
- @id.hash ^ @bridge.hash
48
+ [@id, @bridge].hash
49
49
  end
50
50
 
51
51
  #
@@ -81,7 +81,6 @@ module Selenium
81
81
  private
82
82
 
83
83
  attr_reader :bridge
84
-
85
84
  end # ShadowRoot
86
85
  end # WebDriver
87
86
  end # Selenium
@@ -26,6 +26,7 @@ module Selenium
26
26
  class SocketLock
27
27
  def initialize(port, timeout)
28
28
  @port = port
29
+ @server = nil
29
30
  @timeout = timeout
30
31
  end
31
32
 
@@ -66,11 +67,10 @@ module Selenium
66
67
 
67
68
  def can_lock?
68
69
  @server = TCPServer.new(Platform.localhost, @port)
69
- ChildProcess.close_on_exec @server
70
-
70
+ @server.close_on_exec = true
71
71
  true
72
72
  rescue SocketError, Errno::EADDRINUSE, Errno::EBADF => e
73
- WebDriver.logger.debug("#{self}: #{e.message}")
73
+ WebDriver.logger.debug("#{self}: #{e.message}", id: :driver_service)
74
74
  false
75
75
  end
76
76
 
@@ -93,13 +93,13 @@ module Selenium
93
93
  true
94
94
  rescue *NOT_CONNECTED_ERRORS
95
95
  sock&.close
96
- WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
96
+ WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}", id: :driver_service)
97
97
  false
98
98
  end
99
99
  end
100
100
 
101
101
  def socket_writable?(sock)
102
- IO.select(nil, [sock], nil, CONNECT_TIMEOUT)
102
+ sock.wait_writable(CONNECT_TIMEOUT)
103
103
  end
104
104
 
105
105
  def conn_completed?(sock)
@@ -32,8 +32,8 @@ module Selenium
32
32
  def save_screenshot(png_path, full_page: false)
33
33
  extension = File.extname(png_path).downcase
34
34
  if extension != '.png'
35
- WebDriver.logger.warn "name used for saved screenshot does not match file type. "\
36
- "It should end with .png extension",
35
+ WebDriver.logger.warn 'name used for saved screenshot does not match file type. ' \
36
+ 'It should end with .png extension',
37
37
  id: :screenshot
38
38
  end
39
39
  File.open(png_path, 'wb') { |f| f << screenshot_as(:png, full_page: full_page) }
@@ -60,7 +60,6 @@ module Selenium
60
60
  rescue NameError
61
61
  raise Error::UnsupportedOperationError, "Full Page Screenshots are not supported for #{inspect}"
62
62
  end
63
-
64
63
  end # TakesScreenshot
65
64
  end # WebDriver
66
65
  end # Selenium
@@ -51,9 +51,8 @@ module Selenium
51
51
  #
52
52
 
53
53
  def new_window(type = :window)
54
- unless %i[window tab].include?(type)
55
- raise ArgumentError, "Valid types are :tab and :window, received: #{type.inspect}"
56
- end
54
+ raise ArgumentError, "Valid types are :tab and :window, received: #{type.inspect}" unless %i[window
55
+ tab].include?(type)
57
56
 
58
57
  handle = @bridge.new_window(type)['handle']
59
58
 
@@ -48,7 +48,7 @@ module Selenium
48
48
  def script
49
49
  Float(@bridge.timeouts['script']) / 1000
50
50
  end
51
- alias_method :script_timeout, :script
51
+ alias script_timeout script
52
52
 
53
53
  #
54
54
  # Sets the amount of time to wait for an asynchronous script to finish
@@ -59,7 +59,7 @@ module Selenium
59
59
  def script=(seconds)
60
60
  @bridge.timeouts = {'script' => Integer(seconds * 1000)}
61
61
  end
62
- alias_method :script_timeout=, :script=
62
+ alias script_timeout= script=
63
63
 
64
64
  #
65
65
  # Gets the amount of time to wait for a page load to complete before throwing an error.
@@ -0,0 +1,85 @@
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
+ #
21
+ # A credential stored in a virtual authenticator.
22
+ # @see https://w3c.github.io/webauthn/#credential-parameters
23
+ #
24
+
25
+ module Selenium
26
+ module WebDriver
27
+ class Credential
28
+ class << self
29
+ def resident(**opts)
30
+ Credential.new(resident_credential: true, **opts)
31
+ end
32
+
33
+ def non_resident(**opts)
34
+ Credential.new(resident_credential: false, **opts)
35
+ end
36
+
37
+ def encode(byte_array)
38
+ Base64.urlsafe_encode64(byte_array&.pack('C*'))
39
+ end
40
+
41
+ def decode(base64)
42
+ Base64.urlsafe_decode64(base64).unpack('C*')
43
+ end
44
+
45
+ def from_json(opts)
46
+ user_handle = opts['userHandle'] ? decode(opts['userHandle']) : nil
47
+ new(id: decode(opts['credentialId']),
48
+ resident_credential: opts['isResidentCredential'],
49
+ rp_id: opts['rpId'],
50
+ private_key: opts['privateKey'],
51
+ sign_count: opts['signCount'],
52
+ user_handle: user_handle)
53
+ end
54
+ end
55
+
56
+ attr_reader :id, :resident_credential, :rp_id, :user_handle, :private_key, :sign_count
57
+ alias resident_credential? resident_credential
58
+
59
+ def initialize(id:, resident_credential:, rp_id:, private_key:, **opts)
60
+ @id = id
61
+ @resident_credential = resident_credential
62
+ @rp_id = rp_id
63
+ @user_handle = opts.delete(:user_handle) { nil }
64
+ @private_key = private_key
65
+ @sign_count = opts.delete(:sign_count) { 0 }
66
+
67
+ raise ArgumentError, "Invalid arguments: #{opts.keys}" unless opts.empty?
68
+ end
69
+
70
+ #
71
+ # @api private
72
+ #
73
+
74
+ def as_json(*)
75
+ credential_data = {'credentialId' => Credential.encode(id),
76
+ 'isResidentCredential' => resident_credential?,
77
+ 'rpId' => rp_id,
78
+ 'privateKey' => Credential.encode(private_key),
79
+ 'signCount' => sign_count}
80
+ credential_data['userHandle'] = Credential.encode(user_handle) if user_handle
81
+ credential_data
82
+ end
83
+ end # Credential
84
+ end # WebDriver
85
+ end # Selenium
@@ -0,0 +1,72 @@
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
+ class VirtualAuthenticator
23
+ attr_reader :options
24
+
25
+ #
26
+ # api private
27
+ # Use `Driver#add_virtual_authenticator`
28
+ #
29
+
30
+ def initialize(bridge, authenticator_id, options)
31
+ @id = authenticator_id
32
+ @bridge = bridge
33
+ @options = options
34
+ @valid = true
35
+ end
36
+
37
+ def add_credential(credential)
38
+ credential = credential.as_json
39
+ @bridge.add_credential credential, @id
40
+ end
41
+
42
+ def credentials
43
+ credential_data = @bridge.credentials @id
44
+ credential_data.map do |cred|
45
+ Credential.from_json(cred)
46
+ end
47
+ end
48
+
49
+ def remove_credential(credential_id)
50
+ credential_id = Credential.encode(credential_id) if credential_id.instance_of?(Array)
51
+ @bridge.remove_credential credential_id, @id
52
+ end
53
+
54
+ def remove_all_credentials
55
+ @bridge.remove_all_credentials @id
56
+ end
57
+
58
+ def user_verified=(verified)
59
+ @bridge.user_verified verified, @id
60
+ end
61
+
62
+ def remove!
63
+ @bridge.remove_virtual_authenticator(@id)
64
+ @valid = false
65
+ end
66
+
67
+ def valid?
68
+ @valid
69
+ end
70
+ end # VirtualAuthenticator
71
+ end # WebDriver
72
+ end # Selenium
@@ -0,0 +1,62 @@
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
+ #
21
+ # Options for the creation of virtual authenticators.
22
+ # @see http://w3c.github.io/webauthn/#sctn-automation
23
+ #
24
+
25
+ module Selenium
26
+ module WebDriver
27
+ class VirtualAuthenticatorOptions
28
+ PROTOCOL = {ctap2: 'ctap2', u2f: 'ctap1/u2f'}.freeze
29
+ TRANSPORT = {ble: 'ble', usb: 'usb', nfc: 'nfc', internal: 'internal'}.freeze
30
+
31
+ attr_accessor :protocol, :transport, :resident_key, :user_verification, :user_consenting, :user_verified
32
+ alias resident_key? resident_key
33
+ alias user_verification? user_verification
34
+ alias user_consenting? user_consenting
35
+ alias user_verified? user_verified
36
+
37
+ def initialize(**opts)
38
+ @protocol = opts.delete(:protocol) { :ctap2 }
39
+ @transport = opts.delete(:transport) { :usb }
40
+ @resident_key = opts.delete(:resident_key) { false }
41
+ @user_verification = opts.delete(:user_verification) { false }
42
+ @user_consenting = opts.delete(:user_consenting) { true }
43
+ @user_verified = opts.delete(:user_verified) { false }
44
+
45
+ raise ArgumentError, "Invalid arguments: #{opts.keys}" unless opts.empty?
46
+ end
47
+
48
+ #
49
+ # @api private
50
+ #
51
+
52
+ def as_json(*)
53
+ {'protocol' => PROTOCOL[protocol],
54
+ 'transport' => TRANSPORT[transport],
55
+ 'hasResidentKey' => resident_key?,
56
+ 'hasUserVerification' => user_verification?,
57
+ 'isUserConsenting' => user_consenting?,
58
+ 'isUserVerified' => user_verified?}
59
+ end
60
+ end # VirtualAuthenticatorOptions
61
+ end # WebDriver
62
+ end # Selenium