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
@@ -74,7 +74,7 @@ module Selenium
74
74
  def ==(other)
75
75
  other.is_a?(self.class) && as_json == other.as_json
76
76
  end
77
- alias_method :eql?, :==
77
+ alias eql? ==
78
78
 
79
79
  def ftp=(value)
80
80
  self.type = :manual
@@ -152,7 +152,7 @@ module Selenium
152
152
  'socksUsername' => socks_username,
153
153
  'socksPassword' => socks_password,
154
154
  'socksVersion' => socks_version
155
- }.delete_if { |_k, v| v.nil? }
155
+ }.compact
156
156
 
157
157
  json_result if json_result.length > 1
158
158
  end
@@ -0,0 +1,134 @@
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) && browser_path && !browser_path.empty?
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
+ location = ENV.fetch('SE_MANAGER_PATH', begin
79
+ directory = File.expand_path(bin_path, __FILE__)
80
+ if Platform.windows?
81
+ "#{directory}/windows/selenium-manager.exe"
82
+ elsif Platform.mac?
83
+ "#{directory}/macos/selenium-manager"
84
+ elsif Platform.linux?
85
+ "#{directory}/linux/selenium-manager"
86
+ end
87
+ end)
88
+
89
+ validate_location(location)
90
+ location
91
+ end
92
+ end
93
+
94
+ def validate_location(location)
95
+ begin
96
+ Platform.assert_file(location)
97
+ Platform.assert_executable(location)
98
+ rescue TypeError
99
+ raise Error::WebDriverError,
100
+ "Unable to locate or obtain Selenium Manager binary; #{location} is not a valid file object"
101
+ rescue Error::WebDriverError => e
102
+ raise Error::WebDriverError, "Selenium Manager binary located, but #{e.message}"
103
+ end
104
+
105
+ WebDriver.logger.debug("Selenium Manager binary found at #{location}", id: :selenium_manager)
106
+ end
107
+
108
+ def run(*command)
109
+ command += %w[--output json]
110
+ command << '--debug' if WebDriver.logger.debug?
111
+
112
+ WebDriver.logger.debug("Executing Process #{command}", id: :selenium_manager)
113
+
114
+ begin
115
+ stdout, stderr, status = Open3.capture3(*command)
116
+ rescue StandardError => e
117
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}; #{e.message}"
118
+ end
119
+
120
+ json_output = stdout.empty? ? {} : JSON.parse(stdout)
121
+ (json_output['logs'] || []).each do |log|
122
+ level = log['level'].casecmp('info').zero? ? 'debug' : log['level'].downcase
123
+ WebDriver.logger.send(level, log['message'], id: :selenium_manager)
124
+ end
125
+
126
+ result = json_output['result']
127
+ return result unless status.exitstatus.positive?
128
+
129
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{result}#{stderr}"
130
+ end
131
+ end
132
+ end # SeleniumManager
133
+ end # WebDriver
134
+ 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,37 @@ 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
+ @executable_path ||= begin
91
+ default_options = WebDriver.const_get("#{self.class.name.split('::')[2]}::Options").new
92
+ DriverFinder.path(default_options, self.class)
93
+ end
94
+ ServiceManager.new(self).tap(&:start)
86
95
  end
87
96
 
88
97
  def shutdown_supported
89
98
  self.class::SHUTDOWN_SUPPORTED
90
99
  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
100
  end # Service
110
101
  end # WebDriver
111
102
  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
+ @io = config.log
44
+ @extra_args = config.args
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.
@@ -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