selenium-webdriver 4.2.1 → 4.15.0

Sign up to get free protection for your applications and to get access to all the features.
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