selenium-webdriver 4.5.0 → 4.16.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.
- checksums.yaml +4 -4
- data/CHANGES +219 -1
- data/Gemfile +3 -0
- data/LICENSE +1 -1
- data/NOTICE +1 -1
- data/README.md +2 -2
- 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 +8 -22
- data/lib/selenium/webdriver/atoms/findElements.js +5 -5
- data/lib/selenium/webdriver/atoms/getAttribute.js +0 -0
- data/lib/selenium/webdriver/atoms/isDisplayed.js +2 -1
- data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
- data/lib/selenium/webdriver/atoms.rb +5 -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/{common/driver_extensions/has_location.rb → bidi/log/filter_by.rb} +14 -11
- 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 +13 -0
- data/lib/selenium/webdriver/bidi.rb +3 -2
- data/lib/selenium/webdriver/chrome/driver.rb +9 -30
- data/lib/selenium/webdriver/chrome/features.rb +8 -71
- data/lib/selenium/webdriver/chrome/options.rb +3 -237
- data/lib/selenium/webdriver/chrome/profile.rb +3 -83
- data/lib/selenium/webdriver/chrome/service.rb +4 -19
- data/lib/selenium/webdriver/chrome.rb +0 -2
- data/lib/selenium/webdriver/chromium/driver.rb +60 -0
- data/lib/selenium/webdriver/chromium/features.rb +99 -0
- data/lib/selenium/webdriver/chromium/options.rb +243 -0
- data/lib/selenium/webdriver/chromium/profile.rb +113 -0
- data/lib/selenium/webdriver/chromium.rb +29 -0
- data/lib/selenium/webdriver/common/action_builder.rb +11 -58
- data/lib/selenium/webdriver/common/child_process.rb +124 -0
- data/lib/selenium/webdriver/common/driver.rb +19 -36
- 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_bidi.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +0 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +0 -2
- 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_file_downloads.rb +65 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +0 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +0 -2
- data/lib/selenium/webdriver/common/driver_finder.rb +45 -0
- data/lib/selenium/webdriver/common/element.rb +6 -6
- data/lib/selenium/webdriver/common/error.rb +27 -4
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +3 -3
- data/lib/selenium/webdriver/common/interactions/pointer_move.rb +2 -2
- data/lib/selenium/webdriver/common/interactions/scroll.rb +7 -5
- data/lib/selenium/webdriver/common/local_driver.rb +46 -0
- data/lib/selenium/webdriver/common/logger.rb +91 -26
- data/lib/selenium/webdriver/common/options.rb +15 -8
- data/lib/selenium/webdriver/common/platform.rb +8 -49
- 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 +2 -2
- data/lib/selenium/webdriver/common/selenium_manager.rb +140 -0
- data/lib/selenium/webdriver/common/service.rb +21 -30
- data/lib/selenium/webdriver/common/service_manager.rb +6 -12
- data/lib/selenium/webdriver/common/shadow_root.rb +1 -2
- data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
- data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
- 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 +8 -6
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +0 -1
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +16 -16
- data/lib/selenium/webdriver/common/websocket_connection.rb +12 -4
- data/lib/selenium/webdriver/common.rb +5 -2
- 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 +4 -7
- data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
- data/lib/selenium/webdriver/devtools/request.rb +0 -2
- data/lib/selenium/webdriver/devtools/response.rb +0 -2
- data/lib/selenium/webdriver/devtools.rb +11 -2
- data/lib/selenium/webdriver/edge/driver.rb +9 -3
- data/lib/selenium/webdriver/edge/features.rb +7 -4
- data/lib/selenium/webdriver/edge/options.rb +17 -5
- data/lib/selenium/webdriver/edge/profile.rb +2 -2
- data/lib/selenium/webdriver/edge/service.rb +8 -7
- data/lib/selenium/webdriver/edge.rb +0 -2
- data/lib/selenium/webdriver/firefox/driver.rb +8 -2
- data/lib/selenium/webdriver/firefox/features.rb +5 -2
- data/lib/selenium/webdriver/firefox/options.rb +2 -14
- data/lib/selenium/webdriver/firefox/profile.rb +10 -8
- data/lib/selenium/webdriver/firefox/service.rb +0 -18
- data/lib/selenium/webdriver/ie/driver.rb +7 -1
- data/lib/selenium/webdriver/{common/driver_extensions/has_network_connection.rb → ie/features.rb} +8 -11
- data/lib/selenium/webdriver/ie/options.rb +4 -3
- data/lib/selenium/webdriver/ie/service.rb +0 -22
- data/lib/selenium/webdriver/ie.rb +4 -3
- data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +0 -8
- data/lib/selenium/webdriver/remote/bridge.rb +13 -37
- data/lib/selenium/webdriver/remote/capabilities.rb +3 -53
- data/lib/selenium/webdriver/remote/driver.rb +35 -13
- data/lib/selenium/webdriver/remote/features.rb +75 -0
- 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 +2 -2
- data/lib/selenium/webdriver/remote/response.rb +0 -1
- data/lib/selenium/webdriver/remote/server_error.rb +1 -1
- data/lib/selenium/webdriver/remote.rb +1 -1
- data/lib/selenium/webdriver/safari/driver.rb +7 -1
- data/lib/selenium/webdriver/safari/features.rb +5 -3
- data/lib/selenium/webdriver/safari/options.rb +5 -1
- data/lib/selenium/webdriver/safari/service.rb +10 -4
- data/lib/selenium/webdriver/safari.rb +1 -1
- data/lib/selenium/webdriver/support/color.rb +17 -17
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +2 -2
- data/lib/selenium/webdriver/support/guards/guard.rb +6 -5
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +0 -2
- 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 +2 -5
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +5 -4
- data/selenium-webdriver.gemspec +10 -11
- metadata +43 -84
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
|
@@ -40,7 +40,8 @@ module Selenium
|
|
|
40
40
|
@executable_path = config.executable_path
|
|
41
41
|
@host = Platform.localhost
|
|
42
42
|
@port = config.port
|
|
43
|
-
@
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
@@ -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[
|
|
48
|
-
resident_credential: opts[
|
|
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
|
-
|
|
57
|
+
alias resident_credential? resident_credential
|
|
58
58
|
|
|
59
|
-
def initialize(id:, resident_credential:, rp_id:, private_key:,
|
|
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
|
#
|
|
@@ -25,24 +25,24 @@
|
|
|
25
25
|
module Selenium
|
|
26
26
|
module WebDriver
|
|
27
27
|
class VirtualAuthenticatorOptions
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def initialize(
|
|
39
|
-
|
|
40
|
-
@
|
|
41
|
-
@
|
|
42
|
-
@
|
|
43
|
-
@
|
|
44
|
-
@
|
|
45
|
-
|
|
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[
|
|
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'
|
|
@@ -65,10 +68,8 @@ require 'selenium/webdriver/common/html5/local_storage'
|
|
|
65
68
|
require 'selenium/webdriver/common/html5/session_storage'
|
|
66
69
|
require 'selenium/webdriver/common/driver_extensions/has_web_storage'
|
|
67
70
|
require 'selenium/webdriver/common/driver_extensions/downloads_files'
|
|
68
|
-
require 'selenium/webdriver/common/driver_extensions/has_location'
|
|
69
71
|
require 'selenium/webdriver/common/driver_extensions/has_session_id'
|
|
70
72
|
require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
|
|
71
|
-
require 'selenium/webdriver/common/driver_extensions/has_network_connection'
|
|
72
73
|
require 'selenium/webdriver/common/driver_extensions/has_network_interception'
|
|
73
74
|
require 'selenium/webdriver/common/driver_extensions/has_apple_permissions'
|
|
74
75
|
require 'selenium/webdriver/common/driver_extensions/has_permissions'
|
|
@@ -80,6 +81,7 @@ require 'selenium/webdriver/common/driver_extensions/full_page_screenshot'
|
|
|
80
81
|
require 'selenium/webdriver/common/driver_extensions/has_addons'
|
|
81
82
|
require 'selenium/webdriver/common/driver_extensions/has_bidi'
|
|
82
83
|
require 'selenium/webdriver/common/driver_extensions/has_devtools'
|
|
84
|
+
require 'selenium/webdriver/common/driver_extensions/has_file_downloads'
|
|
83
85
|
require 'selenium/webdriver/common/driver_extensions/has_authentication'
|
|
84
86
|
require 'selenium/webdriver/common/driver_extensions/has_logs'
|
|
85
87
|
require 'selenium/webdriver/common/driver_extensions/has_log_events'
|
|
@@ -95,3 +97,4 @@ require 'selenium/webdriver/common/driver'
|
|
|
95
97
|
require 'selenium/webdriver/common/element'
|
|
96
98
|
require 'selenium/webdriver/common/shadow_root'
|
|
97
99
|
require 'selenium/webdriver/common/websocket_connection'
|
|
100
|
+
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
@@ -21,7 +21,6 @@ module Selenium
|
|
|
21
21
|
module WebDriver
|
|
22
22
|
class DevTools
|
|
23
23
|
class Response
|
|
24
|
-
|
|
25
24
|
attr_accessor :code, :body, :headers
|
|
26
25
|
attr_reader :id
|
|
27
26
|
|
|
@@ -59,7 +58,6 @@ module Selenium
|
|
|
59
58
|
def inspect
|
|
60
59
|
%(#<#{self.class.name} @id="#{id}" @code="#{code}")
|
|
61
60
|
end
|
|
62
|
-
|
|
63
61
|
end # Response
|
|
64
62
|
end # DevTools
|
|
65
63
|
end # WebDriver
|
|
@@ -52,7 +52,17 @@ module Selenium
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def method_missing(method, *_args)
|
|
55
|
-
|
|
55
|
+
namespace = "Selenium::DevTools::V#{Selenium::DevTools.version}"
|
|
56
|
+
methods_to_classes = "#{namespace}::METHODS_TO_CLASSES"
|
|
57
|
+
|
|
58
|
+
desired_class = if Object.const_defined?(methods_to_classes)
|
|
59
|
+
# selenium-devtools 0.113 and newer
|
|
60
|
+
"#{namespace}::#{Object.const_get(methods_to_classes)[method]}"
|
|
61
|
+
else
|
|
62
|
+
# selenium-devtools 0.112 and older
|
|
63
|
+
"#{namespace}::#{method.capitalize}"
|
|
64
|
+
end
|
|
65
|
+
|
|
56
66
|
return unless Object.const_defined?(desired_class)
|
|
57
67
|
|
|
58
68
|
self.class.class_eval do
|
|
@@ -81,7 +91,6 @@ module Selenium
|
|
|
81
91
|
def error_message(error)
|
|
82
92
|
[error['code'], error['message'], error['data']].join(': ')
|
|
83
93
|
end
|
|
84
|
-
|
|
85
94
|
end # DevTools
|
|
86
95
|
end # WebDriver
|
|
87
96
|
end # Selenium
|
|
@@ -17,18 +17,24 @@
|
|
|
17
17
|
# specific language governing permissions and limitations
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
|
-
require 'selenium/webdriver/
|
|
20
|
+
require 'selenium/webdriver/chromium/driver'
|
|
21
21
|
|
|
22
22
|
module Selenium
|
|
23
23
|
module WebDriver
|
|
24
24
|
module Edge
|
|
25
|
-
|
|
26
25
|
#
|
|
27
26
|
# Driver implementation for Microsoft Edge.
|
|
28
27
|
# @api private
|
|
29
28
|
#
|
|
30
29
|
|
|
31
|
-
class Driver <
|
|
30
|
+
class Driver < Chromium::Driver
|
|
31
|
+
include LocalDriver
|
|
32
|
+
|
|
33
|
+
def initialize(options: nil, service: nil, url: nil, **opts)
|
|
34
|
+
caps, url = initialize_local_driver(options, service, url)
|
|
35
|
+
super(caps: caps, url: url, **opts)
|
|
36
|
+
end
|
|
37
|
+
|
|
32
38
|
def browser
|
|
33
39
|
:edge
|
|
34
40
|
end
|
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
# specific language governing permissions and limitations
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
|
-
require 'selenium/webdriver/
|
|
20
|
+
require 'selenium/webdriver/chromium/features'
|
|
21
21
|
|
|
22
22
|
module Selenium
|
|
23
23
|
module WebDriver
|
|
24
24
|
module Edge
|
|
25
25
|
module Features
|
|
26
|
-
|
|
27
|
-
include WebDriver::Chrome::Features
|
|
26
|
+
include WebDriver::Chromium::Features
|
|
28
27
|
|
|
29
28
|
EDGE_COMMANDS = {
|
|
30
29
|
get_cast_sinks: [:get, 'session/:session_id/ms/cast/get_sinks'],
|
|
@@ -36,8 +35,12 @@ module Selenium
|
|
|
36
35
|
send_command: [:post, 'session/:session_id/ms/cdp/execute']
|
|
37
36
|
}.freeze
|
|
38
37
|
|
|
38
|
+
def command_list
|
|
39
|
+
EDGE_COMMANDS.merge(CHROMIUM_COMMANDS).merge(self.class::COMMANDS)
|
|
40
|
+
end
|
|
41
|
+
|
|
39
42
|
def commands(command)
|
|
40
|
-
|
|
43
|
+
command_list[command]
|
|
41
44
|
end
|
|
42
45
|
end # Bridge
|
|
43
46
|
end # Edge
|
|
@@ -17,23 +17,35 @@
|
|
|
17
17
|
# specific language governing permissions and limitations
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
|
-
require 'selenium/webdriver/
|
|
20
|
+
require 'selenium/webdriver/chromium/options'
|
|
21
21
|
|
|
22
22
|
module Selenium
|
|
23
23
|
module WebDriver
|
|
24
24
|
module Edge
|
|
25
|
-
class Options <
|
|
25
|
+
class Options < Chromium::Options
|
|
26
26
|
KEY = 'ms:edgeOptions'
|
|
27
27
|
BROWSER = 'MicrosoftEdge'
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
#
|
|
30
|
+
# Changes the browser name enable webview2
|
|
31
|
+
# see: https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/webdriver
|
|
32
|
+
# Automation of WebView2 apps with Microsoft Edge WebDriver
|
|
33
|
+
#
|
|
34
|
+
# @example Enable webview2
|
|
35
|
+
# options = Selenium::WebDriver::Edge::Options.new
|
|
36
|
+
# options.webview2!
|
|
37
|
+
#
|
|
30
38
|
|
|
31
|
-
def
|
|
32
|
-
|
|
39
|
+
def webview2!
|
|
40
|
+
@options[:browser_name] = 'webview2'
|
|
33
41
|
end
|
|
34
42
|
|
|
35
43
|
private
|
|
36
44
|
|
|
45
|
+
def enable_logging(browser_options)
|
|
46
|
+
browser_options['ms:loggingPrefs'] = @logging_prefs
|
|
47
|
+
end
|
|
48
|
+
|
|
37
49
|
def binary_path
|
|
38
50
|
Edge.path
|
|
39
51
|
end
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
# specific language governing permissions and limitations
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
|
-
require 'selenium/webdriver/
|
|
20
|
+
require 'selenium/webdriver/chromium/profile'
|
|
21
21
|
|
|
22
22
|
module Selenium
|
|
23
23
|
module WebDriver
|
|
@@ -26,7 +26,7 @@ module Selenium
|
|
|
26
26
|
# @private
|
|
27
27
|
#
|
|
28
28
|
|
|
29
|
-
class Profile <
|
|
29
|
+
class Profile < Chromium::Profile
|
|
30
30
|
end # Profile
|
|
31
31
|
end # Edge
|
|
32
32
|
end # WebDriver
|
|
@@ -17,19 +17,20 @@
|
|
|
17
17
|
# specific language governing permissions and limitations
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
|
-
require 'selenium/webdriver/chrome/service'
|
|
21
|
-
|
|
22
20
|
module Selenium
|
|
23
21
|
module WebDriver
|
|
24
22
|
module Edge
|
|
25
|
-
class Service <
|
|
23
|
+
class Service < WebDriver::Service
|
|
26
24
|
DEFAULT_PORT = 9515
|
|
27
25
|
EXECUTABLE = 'msedgedriver'
|
|
28
|
-
MISSING_TEXT = <<~ERROR
|
|
29
|
-
Unable to find msedgedriver. Please download the server from
|
|
30
|
-
https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ and place it somewhere on your PATH.
|
|
31
|
-
ERROR
|
|
32
26
|
SHUTDOWN_SUPPORTED = true
|
|
27
|
+
|
|
28
|
+
def log
|
|
29
|
+
return @log unless @log.is_a? String
|
|
30
|
+
|
|
31
|
+
@args << "--log-path=#{@log}"
|
|
32
|
+
@log = nil
|
|
33
|
+
end
|
|
33
34
|
end # Service
|
|
34
35
|
end # Edge
|
|
35
36
|
end # WebDriver
|