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.
- checksums.yaml +4 -4
- data/CHANGES +234 -1
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/NOTICE +1 -1
- data/README.md +1 -1
- data/bin/linux/selenium-manager +0 -0
- data/bin/macos/selenium-manager +0 -0
- data/bin/windows/selenium-manager.exe +0 -0
- data/lib/selenium/server.rb +36 -27
- data/lib/selenium/webdriver/atoms/findElements.js +0 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +0 -0
- data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
- data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
- data/lib/selenium/webdriver/atoms.rb +2 -3
- data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
- data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/filter_by.rb +40 -0
- data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
- data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
- data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
- data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
- data/lib/selenium/webdriver/bidi/session.rb +51 -0
- data/lib/selenium/webdriver/bidi.rb +56 -0
- data/lib/selenium/webdriver/chrome/driver.rb +9 -29
- data/lib/selenium/webdriver/chrome/features.rb +6 -68
- data/lib/selenium/webdriver/chrome/options.rb +3 -223
- data/lib/selenium/webdriver/chrome/profile.rb +3 -83
- data/lib/selenium/webdriver/chrome/service.rb +3 -23
- data/lib/selenium/webdriver/chrome.rb +0 -14
- data/lib/selenium/webdriver/chromium/driver.rb +61 -0
- data/lib/selenium/webdriver/chromium/features.rb +103 -0
- data/lib/selenium/webdriver/chromium/options.rb +261 -0
- data/lib/selenium/webdriver/chromium/profile.rb +113 -0
- data/lib/selenium/webdriver/chromium/service.rb +42 -0
- data/lib/selenium/webdriver/chromium.rb +32 -0
- data/lib/selenium/webdriver/common/action_builder.rb +64 -22
- data/lib/selenium/webdriver/common/child_process.rb +124 -0
- data/lib/selenium/webdriver/common/driver.rb +36 -74
- data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +10 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +1 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -69
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -3
- data/lib/selenium/webdriver/common/driver_finder.rb +44 -0
- data/lib/selenium/webdriver/common/element.rb +8 -8
- data/lib/selenium/webdriver/common/error.rb +1 -3
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
- data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
- data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
- data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
- data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
- data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
- data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
- data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
- data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
- data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
- data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
- data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
- data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
- data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
- data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
- data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
- data/lib/selenium/webdriver/common/keys.rb +1 -0
- data/lib/selenium/webdriver/common/local_driver.rb +55 -0
- data/lib/selenium/webdriver/common/logger.rb +76 -24
- data/lib/selenium/webdriver/common/manager.rb +0 -27
- data/lib/selenium/webdriver/common/options.rb +32 -17
- data/lib/selenium/webdriver/common/platform.rb +8 -5
- data/lib/selenium/webdriver/common/port_prober.rb +1 -1
- data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
- data/lib/selenium/webdriver/common/proxy.rb +1 -1
- data/lib/selenium/webdriver/common/search_context.rb +0 -6
- data/lib/selenium/webdriver/common/selenium_manager.rb +108 -0
- data/lib/selenium/webdriver/common/service.rb +20 -23
- data/lib/selenium/webdriver/common/service_manager.rb +8 -15
- data/lib/selenium/webdriver/common/shadow_root.rb +2 -3
- data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
- data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
- data/lib/selenium/webdriver/common/takes_screenshot.rb +2 -3
- data/lib/selenium/webdriver/common/target_locator.rb +2 -3
- data/lib/selenium/webdriver/common/timeouts.rb +2 -2
- data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
- data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
- data/lib/selenium/webdriver/common/window.rb +6 -6
- data/lib/selenium/webdriver/common/zipper.rb +1 -1
- data/lib/selenium/webdriver/common.rb +21 -3
- data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
- data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
- data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
- data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
- data/lib/selenium/webdriver/devtools/request.rb +1 -3
- data/lib/selenium/webdriver/devtools/response.rb +1 -3
- data/lib/selenium/webdriver/devtools.rb +17 -114
- data/lib/selenium/webdriver/edge/driver.rb +9 -3
- data/lib/selenium/webdriver/edge/features.rb +4 -4
- data/lib/selenium/webdriver/edge/options.rb +3 -5
- data/lib/selenium/webdriver/edge/profile.rb +2 -2
- data/lib/selenium/webdriver/edge/service.rb +2 -6
- data/lib/selenium/webdriver/firefox/driver.rb +9 -2
- data/lib/selenium/webdriver/firefox/features.rb +6 -6
- data/lib/selenium/webdriver/firefox/options.rb +9 -3
- data/lib/selenium/webdriver/firefox/profile.rb +8 -12
- data/lib/selenium/webdriver/firefox/service.rb +0 -6
- data/lib/selenium/webdriver/firefox/util.rb +46 -0
- data/lib/selenium/webdriver/firefox.rb +1 -14
- data/lib/selenium/webdriver/ie/driver.rb +7 -1
- data/lib/selenium/webdriver/ie/service.rb +1 -7
- data/lib/selenium/webdriver/ie.rb +0 -14
- data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +15 -8
- data/lib/selenium/webdriver/remote/bridge.rb +65 -35
- data/lib/selenium/webdriver/remote/capabilities.rb +34 -12
- data/lib/selenium/webdriver/remote/driver.rb +19 -14
- data/lib/selenium/webdriver/remote/http/common.rb +3 -3
- data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
- data/lib/selenium/webdriver/remote/http/default.rb +7 -12
- data/lib/selenium/webdriver/remote/response.rb +2 -3
- data/lib/selenium/webdriver/remote.rb +0 -1
- data/lib/selenium/webdriver/safari/driver.rb +7 -1
- data/lib/selenium/webdriver/safari/features.rb +0 -2
- data/lib/selenium/webdriver/safari/options.rb +5 -1
- data/lib/selenium/webdriver/safari/service.rb +0 -4
- data/lib/selenium/webdriver/safari.rb +1 -15
- data/lib/selenium/webdriver/support/color.rb +22 -22
- data/lib/selenium/webdriver/support/guards/guard.rb +0 -2
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -3
- data/lib/selenium/webdriver/support/guards.rb +1 -1
- data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
- data/lib/selenium/webdriver/support/select.rb +3 -1
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +5 -4
- data/selenium-webdriver.gemspec +13 -12
- metadata +70 -73
- data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
- 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
|
-
|
|
42
|
+
alias internet_explorer ie
|
|
43
43
|
|
|
44
44
|
def edge(**opts)
|
|
45
45
|
Edge::Service.new(**opts)
|
|
46
46
|
end
|
|
47
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
@
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
45
|
+
alias eql? ==
|
|
46
46
|
|
|
47
47
|
def hash
|
|
48
|
-
@id
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
36
|
-
|
|
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
|
|
55
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|