selenium-webdriver 4.4.0 → 4.11.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +177 -1
  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 +21 -29
  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 +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 +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 +5 -72
  29. data/lib/selenium/webdriver/chrome/options.rb +3 -237
  30. data/lib/selenium/webdriver/chrome/profile.rb +3 -83
  31. data/lib/selenium/webdriver/chrome/service.rb +0 -22
  32. data/lib/selenium/webdriver/chromium/driver.rb +61 -0
  33. data/lib/selenium/webdriver/chromium/features.rb +103 -0
  34. data/lib/selenium/webdriver/chromium/options.rb +243 -0
  35. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  36. data/lib/selenium/webdriver/chromium.rb +31 -0
  37. data/lib/selenium/webdriver/common/action_builder.rb +11 -56
  38. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  39. data/lib/selenium/webdriver/common/driver.rb +21 -26
  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_bidi.rb +0 -2
  46. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +0 -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 +0 -2
  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 +0 -1
  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 +0 -2
  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 +0 -2
  58. data/lib/selenium/webdriver/common/driver_finder.rb +45 -0
  59. data/lib/selenium/webdriver/common/element.rb +7 -7
  60. data/lib/selenium/webdriver/common/error.rb +27 -4
  61. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  62. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +3 -3
  63. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +2 -2
  64. data/lib/selenium/webdriver/common/interactions/scroll.rb +7 -5
  65. data/lib/selenium/webdriver/common/local_driver.rb +55 -0
  66. data/lib/selenium/webdriver/common/logger.rb +90 -25
  67. data/lib/selenium/webdriver/common/options.rb +11 -8
  68. data/lib/selenium/webdriver/common/platform.rb +4 -50
  69. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  70. data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
  71. data/lib/selenium/webdriver/common/proxy.rb +2 -2
  72. data/lib/selenium/webdriver/common/selenium_manager.rb +131 -0
  73. data/lib/selenium/webdriver/common/service.rb +17 -30
  74. data/lib/selenium/webdriver/common/service_manager.rb +6 -12
  75. data/lib/selenium/webdriver/common/shadow_root.rb +1 -2
  76. data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
  77. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  78. data/lib/selenium/webdriver/common/takes_screenshot.rb +2 -3
  79. data/lib/selenium/webdriver/common/target_locator.rb +2 -3
  80. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  81. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +8 -6
  82. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +0 -1
  83. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +16 -16
  84. data/lib/selenium/webdriver/common/websocket_connection.rb +12 -4
  85. data/lib/selenium/webdriver/common.rb +4 -0
  86. data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
  87. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
  88. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
  89. data/lib/selenium/webdriver/devtools/network_interceptor.rb +4 -7
  90. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
  91. data/lib/selenium/webdriver/devtools/request.rb +0 -2
  92. data/lib/selenium/webdriver/devtools/response.rb +0 -2
  93. data/lib/selenium/webdriver/devtools.rb +11 -2
  94. data/lib/selenium/webdriver/edge/driver.rb +9 -3
  95. data/lib/selenium/webdriver/edge/features.rb +3 -4
  96. data/lib/selenium/webdriver/edge/options.rb +17 -5
  97. data/lib/selenium/webdriver/edge/profile.rb +2 -2
  98. data/lib/selenium/webdriver/edge/service.rb +1 -7
  99. data/lib/selenium/webdriver/firefox/driver.rb +8 -2
  100. data/lib/selenium/webdriver/firefox/features.rb +5 -2
  101. data/lib/selenium/webdriver/firefox/options.rb +3 -14
  102. data/lib/selenium/webdriver/firefox/profile.rb +7 -7
  103. data/lib/selenium/webdriver/firefox/service.rb +0 -18
  104. data/lib/selenium/webdriver/ie/driver.rb +7 -1
  105. data/lib/selenium/webdriver/ie/options.rb +2 -1
  106. data/lib/selenium/webdriver/ie/service.rb +0 -22
  107. data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +0 -2
  108. data/lib/selenium/webdriver/remote/bridge.rb +15 -20
  109. data/lib/selenium/webdriver/remote/capabilities.rb +3 -53
  110. data/lib/selenium/webdriver/remote/driver.rb +19 -13
  111. data/lib/selenium/webdriver/remote/http/common.rb +3 -3
  112. data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
  113. data/lib/selenium/webdriver/remote/http/default.rb +2 -2
  114. data/lib/selenium/webdriver/remote/response.rb +0 -1
  115. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  116. data/lib/selenium/webdriver/remote.rb +0 -1
  117. data/lib/selenium/webdriver/safari/driver.rb +7 -1
  118. data/lib/selenium/webdriver/safari/features.rb +0 -2
  119. data/lib/selenium/webdriver/safari/options.rb +5 -1
  120. data/lib/selenium/webdriver/safari/service.rb +10 -4
  121. data/lib/selenium/webdriver/safari.rb +1 -1
  122. data/lib/selenium/webdriver/support/color.rb +17 -17
  123. data/lib/selenium/webdriver/support/guards/guard.rb +0 -2
  124. data/lib/selenium/webdriver/support/guards/guard_condition.rb +0 -2
  125. data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
  126. data/lib/selenium/webdriver/support/select.rb +3 -1
  127. data/lib/selenium/webdriver/version.rb +1 -1
  128. data/lib/selenium/webdriver.rb +4 -4
  129. data/selenium-webdriver.gemspec +10 -11
  130. metadata +40 -82
  131. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
  132. data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
@@ -0,0 +1,131 @@
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
+ class << self
31
+ attr_writer :bin_path
32
+
33
+ def bin_path
34
+ @bin_path ||= '../../../../../bin'
35
+ end
36
+
37
+ # @param [Options] options browser options.
38
+ # @return [String] the path to the correct driver.
39
+ def driver_path(options)
40
+ command = generate_command(binary, options)
41
+
42
+ output = run(*command)
43
+
44
+ browser_path = output['browser_path']
45
+ driver_path = output['driver_path']
46
+ Platform.assert_executable driver_path
47
+
48
+ if options.respond_to? :binary
49
+ options.binary = browser_path
50
+ options.browser_version = nil
51
+ end
52
+
53
+ driver_path
54
+ end
55
+
56
+ private
57
+
58
+ def generate_command(binary, options)
59
+ command = [binary, '--browser', options.browser_name]
60
+ if options.browser_version
61
+ command << '--browser-version'
62
+ command << options.browser_version
63
+ end
64
+ if options.respond_to?(:binary) && !options.binary.nil?
65
+ command << '--browser-path'
66
+ command << options.binary.gsub('\\', '\\\\\\')
67
+ end
68
+ if options.proxy
69
+ command << '--proxy'
70
+ (command << options.proxy.ssl) || options.proxy.http
71
+ end
72
+ command
73
+ end
74
+
75
+ # @return [String] the path to the correct selenium manager
76
+ def binary
77
+ @binary ||= begin
78
+ path = File.expand_path(bin_path, __FILE__)
79
+ path << if Platform.windows?
80
+ '/windows/selenium-manager.exe'
81
+ elsif Platform.mac?
82
+ '/macos/selenium-manager'
83
+ elsif Platform.linux?
84
+ '/linux/selenium-manager'
85
+ end
86
+ location = File.expand_path(path, __FILE__)
87
+
88
+ begin
89
+ Platform.assert_file(location)
90
+ Platform.assert_executable(location)
91
+ rescue TypeError
92
+ raise Error::WebDriverError,
93
+ "Unable to locate or obtain Selenium Manager binary; #{location} is not a valid file object"
94
+ rescue Error::WebDriverError => e
95
+ raise Error::WebDriverError, "Selenium Manager binary located, but #{e.message}"
96
+ end
97
+
98
+ WebDriver.logger.debug("Selenium Manager binary found at #{location}", id: :selenium_manager)
99
+ location
100
+ end
101
+ end
102
+
103
+ def run(*command)
104
+ command += %w[--output json]
105
+ command << '--debug' if WebDriver.logger.debug?
106
+
107
+ WebDriver.logger.debug("Executing Process #{command}", id: :selenium_manager)
108
+
109
+ begin
110
+ stdout, stderr, status = Open3.capture3(*command)
111
+ json_output = stdout.empty? ? nil : JSON.parse(stdout)
112
+ result = json_output['result']
113
+ rescue StandardError => e
114
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}; #{e.message}"
115
+ end
116
+
117
+ (json_output&.fetch('logs') || []).each do |log|
118
+ level = log['level'].casecmp('info').zero? ? 'debug' : log['level'].downcase
119
+ WebDriver.logger.send(level, log['message'], id: :selenium_manager)
120
+ end
121
+
122
+ if status.exitstatus.positive?
123
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{result}#{stderr}"
124
+ end
125
+
126
+ result
127
+ end
128
+ end
129
+ end # SeleniumManager
130
+ end # WebDriver
131
+ 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,47 +66,33 @@ 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
-
77
- @extra_args = args.is_a?(Hash) ? extract_service_args(args) : args
76
+ @log = case log
77
+ when :stdout
78
+ $stdout
79
+ when :stderr
80
+ $stderr
81
+ else
82
+ log
83
+ end
84
+ @args = args
78
85
 
79
86
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
80
87
  end
81
88
 
82
89
  def launch
83
- sm = ServiceManager.new(self)
84
- sm.start
85
- sm
90
+ ServiceManager.new(self).tap(&:start)
86
91
  end
87
92
 
88
93
  def shutdown_supported
89
94
  self.class::SHUTDOWN_SUPPORTED
90
95
  end
91
-
92
- protected
93
-
94
- def extract_service_args(driver_opts)
95
- driver_opts.key?(:args) ? driver_opts.delete(:args) : []
96
- 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
96
  end # Service
110
97
  end # WebDriver
111
98
  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
@@ -64,7 +65,7 @@ module Selenium
64
65
 
65
66
  stop_server
66
67
  @process.poll_for_exit STOP_TIMEOUT
67
- rescue ChildProcess::TimeoutError
68
+ rescue ChildProcess::TimeoutError, Errno::ECONNREFUSED
68
69
  nil # noop
69
70
  ensure
70
71
  stop_process
@@ -77,14 +78,10 @@ module Selenium
77
78
  private
78
79
 
79
80
  def build_process(*command)
80
- WebDriver.logger.debug("Executing Process #{command}")
81
+ WebDriver.logger.debug("Executing Process #{command}", id: :driver_service)
81
82
  @process = ChildProcess.build(*command)
82
- if WebDriver.logger.debug?
83
- @process.io.stdout = @process.io.stderr = WebDriver.logger.io
84
- elsif Platform.jruby?
85
- # Apparently we need to read the output of drivers on JRuby.
86
- @process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
87
- end
83
+ @io ||= WebDriver.logger.io if WebDriver.logger.debug?
84
+ @process.io = @io if @io
88
85
 
89
86
  @process
90
87
  end
@@ -104,8 +101,6 @@ module Selenium
104
101
 
105
102
  def start_process
106
103
  @process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
107
- # NOTE: this is a bug only in Windows 7
108
- @process.leader = true unless Platform.windows?
109
104
  @process.start
110
105
  end
111
106
 
@@ -113,7 +108,6 @@ module Selenium
113
108
  return if process_exited?
114
109
 
115
110
  @process.stop STOP_TIMEOUT
116
- @process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
117
111
  end
118
112
 
119
113
  def stop_server
@@ -42,7 +42,7 @@ 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
48
  [@id, @bridge].hash
@@ -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,7 +93,7 @@ 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
@@ -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.
@@ -44,8 +44,8 @@ module Selenium
44
44
 
45
45
  def from_json(opts)
46
46
  user_handle = opts['userHandle'] ? decode(opts['userHandle']) : nil
47
- new(id: decode(opts["credentialId"]),
48
- resident_credential: opts["isResidentCredential"],
47
+ new(id: decode(opts['credentialId']),
48
+ resident_credential: opts['isResidentCredential'],
49
49
  rp_id: opts['rpId'],
50
50
  private_key: opts['privateKey'],
51
51
  sign_count: opts['signCount'],
@@ -54,15 +54,17 @@ module Selenium
54
54
  end
55
55
 
56
56
  attr_reader :id, :resident_credential, :rp_id, :user_handle, :private_key, :sign_count
57
- alias_method :resident_credential?, :resident_credential
57
+ alias resident_credential? resident_credential
58
58
 
59
- def initialize(id:, resident_credential:, rp_id:, private_key:, user_handle: nil, sign_count: 0)
59
+ def initialize(id:, resident_credential:, rp_id:, private_key:, **opts)
60
60
  @id = id
61
61
  @resident_credential = resident_credential
62
62
  @rp_id = rp_id
63
- @user_handle = user_handle
63
+ @user_handle = opts.delete(:user_handle) { nil }
64
64
  @private_key = private_key
65
- @sign_count = sign_count
65
+ @sign_count = opts.delete(:sign_count) { 0 }
66
+
67
+ raise ArgumentError, "Invalid arguments: #{opts.keys}" unless opts.empty?
66
68
  end
67
69
 
68
70
  #
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  class VirtualAuthenticator
23
-
24
23
  attr_reader :options
25
24
 
26
25
  #
@@ -25,24 +25,24 @@
25
25
  module Selenium
26
26
  module WebDriver
27
27
  class VirtualAuthenticatorOptions
28
-
29
- PROTOCOL = {ctap2: "ctap2", u2f: "ctap1/u2f"}.freeze
30
- TRANSPORT = {ble: "ble", usb: "usb", nfc: "nfc", internal: "internal"}.freeze
28
+ PROTOCOL = {ctap2: 'ctap2', u2f: 'ctap1/u2f'}.freeze
29
+ TRANSPORT = {ble: 'ble', usb: 'usb', nfc: 'nfc', internal: 'internal'}.freeze
31
30
 
32
31
  attr_accessor :protocol, :transport, :resident_key, :user_verification, :user_consenting, :user_verified
33
- alias_method :resident_key?, :resident_key
34
- alias_method :user_verification?, :user_verification
35
- alias_method :user_consenting?, :user_consenting
36
- alias_method :user_verified?, :user_verified
37
-
38
- def initialize(protocol: :ctap2, transport: :usb, resident_key: false,
39
- user_verification: false, user_consenting: true, user_verified: false)
40
- @protocol = protocol
41
- @transport = transport
42
- @resident_key = resident_key
43
- @user_verification = user_verification
44
- @user_consenting = user_consenting
45
- @user_verified = 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
46
  end
47
47
 
48
48
  #
@@ -22,6 +22,11 @@ require 'websocket'
22
22
  module Selenium
23
23
  module WebDriver
24
24
  class WebSocketConnection
25
+ CONNECTION_ERRORS = [
26
+ Errno::ECONNRESET, # connection is aborted (browser process was killed)
27
+ Errno::EPIPE # broken pipe (browser process was killed)
28
+ ].freeze
29
+
25
30
  RESPONSE_WAIT_TIMEOUT = 30
26
31
  RESPONSE_WAIT_INTERVAL = 0.1
27
32
 
@@ -50,7 +55,7 @@ module Selenium
50
55
  def send_cmd(**payload)
51
56
  id = next_id
52
57
  data = payload.merge(id: id)
53
- WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE]
58
+ WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE], id: :bidi
54
59
  data = JSON.generate(data)
55
60
  out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text')
56
61
  socket.write(out_frame.to_s)
@@ -90,6 +95,8 @@ module Selenium
90
95
  end
91
96
  end
92
97
  end
98
+ rescue *CONNECTION_ERRORS
99
+ Thread.stop
93
100
  end
94
101
  end
95
102
 
@@ -104,8 +111,8 @@ module Selenium
104
111
  return {} if message.empty?
105
112
 
106
113
  message = JSON.parse(message)
107
- messages[message["id"]] = message
108
- WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE]
114
+ messages[message['id']] = message
115
+ WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE], id: :bidi
109
116
 
110
117
  message
111
118
  end
@@ -122,6 +129,8 @@ module Selenium
122
129
  Thread.current.report_on_exception = true
123
130
 
124
131
  yield params
132
+ rescue Error::WebDriverError, *CONNECTION_ERRORS
133
+ Thread.stop
125
134
  end
126
135
  end
127
136
 
@@ -150,7 +159,6 @@ module Selenium
150
159
  @id ||= 0
151
160
  @id += 1
152
161
  end
153
-
154
162
  end # BiDi
155
163
  end # WebDriver
156
164
  end # Selenium
@@ -18,10 +18,13 @@
18
18
  # under the License.
19
19
 
20
20
  require 'selenium/webdriver/common/error'
21
+ require 'selenium/webdriver/common/local_driver'
22
+ require 'selenium/webdriver/common/driver_finder'
21
23
  require 'selenium/webdriver/common/platform'
22
24
  require 'selenium/webdriver/common/proxy'
23
25
  require 'selenium/webdriver/common/log_entry'
24
26
  require 'selenium/webdriver/common/file_reaper'
27
+ require 'selenium/webdriver/common/selenium_manager'
25
28
  require 'selenium/webdriver/common/service'
26
29
  require 'selenium/webdriver/common/service_manager'
27
30
  require 'selenium/webdriver/common/socket_lock'
@@ -95,3 +98,4 @@ require 'selenium/webdriver/common/driver'
95
98
  require 'selenium/webdriver/common/element'
96
99
  require 'selenium/webdriver/common/shadow_root'
97
100
  require 'selenium/webdriver/common/websocket_connection'
101
+ require 'selenium/webdriver/common/child_process'
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class ConsoleEvent
24
-
25
24
  attr_accessor :type, :timestamp, :args
26
25
 
27
26
  def initialize(type:, timestamp:, args:)
@@ -31,7 +30,6 @@ module Selenium
31
30
  arg.key?('value') ? arg['value'] : arg
32
31
  end
33
32
  end
34
-
35
33
  end # ConsoleEvent
36
34
  end # DevTools
37
35
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class ExceptionEvent
24
-
25
24
  attr_accessor :description, :timestamp, :stacktrace
26
25
 
27
26
  def initialize(description:, timestamp:, stacktrace:)
@@ -29,7 +28,6 @@ module Selenium
29
28
  @timestamp = Time.at(timestamp / 1000)
30
29
  @stacktrace = stacktrace
31
30
  end
32
-
33
31
  end # ExceptionEvent
34
32
  end # DevTools
35
33
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class MutationEvent
24
-
25
24
  attr_accessor :element, :attribute_name, :current_value, :old_value
26
25
 
27
26
  def initialize(element:, attribute_name:, current_value:, old_value:)
@@ -30,7 +29,6 @@ module Selenium
30
29
  @current_value = current_value
31
30
  @old_value = old_value
32
31
  end
33
-
34
32
  end # MutationEvent
35
33
  end # DevTools
36
34
  end # WebDriver
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
-
24
23
  #
25
24
  # Wraps the network request/response interception, providing
26
25
  # thread-safety guarantees and handling special cases such as browser
@@ -31,14 +30,13 @@ module Selenium
31
30
  #
32
31
 
33
32
  class NetworkInterceptor
34
-
35
33
  # CDP fails to get body on certain responses (301) and raises:
36
34
  # "Can only get response body on requests captured after headers received."
37
- CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE = "-32000"
35
+ CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE = '-32000'
38
36
 
39
37
  # CDP fails to operate with intercepted requests.
40
38
  # Typical reason is browser cancelling intercepted requests/responses.
41
- INVALID_INTERCEPTION_ID_ERROR_CODE = "-32602"
39
+ INVALID_INTERCEPTION_ID_ERROR_CODE = '-32602'
42
40
 
43
41
  def initialize(devtools)
44
42
  @devtools = devtools
@@ -129,14 +127,14 @@ module Selenium
129
127
  def continue_request(id)
130
128
  devtools.fetch.continue_request(request_id: id)
131
129
  end
132
- alias_method :continue_response, :continue_request
130
+ alias continue_response continue_request
133
131
 
134
132
  def mutate_request(request)
135
133
  devtools.fetch.continue_request(
136
134
  request_id: request.id,
137
135
  url: request.url,
138
136
  method: request.method,
139
- post_data: request.post_data,
137
+ post_data: (Base64.strict_encode64(request.post_data) if request.post_data),
140
138
  headers: request.headers.map do |k, v|
141
139
  {name: k, value: v}
142
140
  end
@@ -169,7 +167,6 @@ module Selenium
169
167
  def cancelled?(network_id)
170
168
  lock.synchronize { !!cancelled_requests.delete(network_id) }
171
169
  end
172
-
173
170
  end # NetworkInterceptor
174
171
  end # DevTools
175
172
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class PinnedScript
24
-
25
24
  attr_accessor :key, :devtools_identifier, :script
26
25
 
27
26
  def initialize(script)
@@ -52,7 +51,6 @@ module Selenium
52
51
  def remove
53
52
  "__webdriver_#{key} = undefined"
54
53
  end
55
-
56
54
  end # PinnedScript
57
55
  end # DevTools
58
56
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class Request
24
-
25
24
  attr_accessor :url, :method, :headers, :post_data
26
25
  attr_reader :id
27
26
 
@@ -60,7 +59,6 @@ module Selenium
60
59
  def inspect
61
60
  %(#<#{self.class.name} @id="#{id}" @method="#{method}" @url="#{url}")
62
61
  end
63
-
64
62
  end # Request
65
63
  end # DevTools
66
64
  end # WebDriver