selenium-webdriver 4.12.0 → 4.23.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 +135 -1
- data/Gemfile +1 -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 +2 -1
- data/lib/selenium/webdriver/atoms/findElements.js +28 -27
- data/lib/selenium/webdriver/atoms/getAttribute.js +6 -100
- data/lib/selenium/webdriver/atoms/isDisplayed.js +24 -96
- data/lib/selenium/webdriver/atoms.rb +6 -3
- data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +1 -1
- data/lib/selenium/webdriver/bidi/log_handler.rb +63 -0
- data/lib/selenium/webdriver/bidi/log_inspector.rb +5 -1
- data/lib/selenium/webdriver/bidi/session.rb +7 -7
- data/lib/selenium/webdriver/bidi/struct.rb +44 -0
- data/lib/selenium/webdriver/bidi.rb +10 -0
- data/lib/selenium/webdriver/chrome/features.rb +5 -1
- data/lib/selenium/webdriver/chrome/service.rb +7 -0
- data/lib/selenium/webdriver/chromium/driver.rb +1 -1
- data/lib/selenium/webdriver/chromium/features.rb +0 -4
- data/lib/selenium/webdriver/common/action_builder.rb +0 -4
- data/lib/selenium/webdriver/common/child_process.rb +8 -2
- data/lib/selenium/webdriver/common/driver.rb +23 -17
- data/lib/selenium/webdriver/common/driver_extensions/has_bidi.rb +1 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_fedcm_dialog.rb +55 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +65 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
- data/lib/selenium/webdriver/common/driver_finder.rb +66 -14
- data/lib/selenium/webdriver/common/error.rb +22 -22
- data/lib/selenium/webdriver/common/fedcm/account.rb +50 -0
- data/lib/selenium/webdriver/common/fedcm/dialog.rb +74 -0
- data/lib/selenium/webdriver/common/fedcm.rb +27 -0
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +0 -1
- data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +1 -1
- data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +2 -1
- data/lib/selenium/webdriver/common/interactions/wheel_input.rb +1 -1
- data/lib/selenium/webdriver/common/local_driver.rb +8 -1
- data/lib/selenium/webdriver/common/logger.rb +7 -7
- data/lib/selenium/webdriver/common/manager.rb +1 -1
- data/lib/selenium/webdriver/common/options.rb +6 -2
- data/lib/selenium/webdriver/common/platform.rb +7 -1
- data/lib/selenium/webdriver/common/proxy.rb +2 -2
- data/lib/selenium/webdriver/common/script.rb +45 -0
- data/lib/selenium/webdriver/common/search_context.rb +10 -2
- data/lib/selenium/webdriver/common/selenium_manager.rb +34 -59
- data/lib/selenium/webdriver/common/service.rb +4 -0
- data/lib/selenium/webdriver/common/service_manager.rb +1 -1
- data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
- data/lib/selenium/webdriver/common/takes_screenshot.rb +4 -2
- data/lib/selenium/webdriver/common/websocket_connection.rb +12 -0
- data/lib/selenium/webdriver/common.rb +5 -2
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +1 -1
- data/lib/selenium/webdriver/edge/features.rb +5 -1
- data/lib/selenium/webdriver/edge/service.rb +7 -0
- data/lib/selenium/webdriver/firefox/features.rb +5 -1
- data/lib/selenium/webdriver/firefox/options.rb +3 -0
- data/lib/selenium/webdriver/firefox/profile.rb +14 -6
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +1 -1
- data/lib/selenium/webdriver/{common/driver_extensions/has_location.rb → ie/features.rb} +8 -10
- data/lib/selenium/webdriver/ie/options.rb +3 -2
- data/lib/selenium/webdriver/ie.rb +4 -3
- data/lib/selenium/webdriver/{common/driver_extensions/has_network_connection.rb → remote/bidi_bridge.rb} +18 -11
- data/lib/selenium/webdriver/remote/bridge/commands.rb +13 -7
- data/lib/selenium/webdriver/remote/bridge/locator_converter.rb +76 -0
- data/lib/selenium/webdriver/remote/bridge.rb +87 -69
- data/lib/selenium/webdriver/remote/capabilities.rb +2 -2
- data/lib/selenium/webdriver/remote/driver.rb +4 -0
- data/lib/selenium/webdriver/remote/features.rb +75 -0
- data/lib/selenium/webdriver/remote/http/common.rb +21 -3
- data/lib/selenium/webdriver/remote/response.rb +8 -33
- data/lib/selenium/webdriver/remote/server_error.rb +1 -1
- data/lib/selenium/webdriver/remote.rb +2 -0
- data/lib/selenium/webdriver/safari/features.rb +5 -1
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
- data/lib/selenium/webdriver/support/guards/guard.rb +14 -12
- data/lib/selenium/webdriver/support/guards.rb +1 -1
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +1 -1
- data/selenium-webdriver.gemspec +9 -7
- metadata +84 -6
@@ -103,7 +103,7 @@ module Selenium
|
|
103
103
|
#
|
104
104
|
# @param [Array, Symbol] ids
|
105
105
|
#
|
106
|
-
def allow(ids)
|
106
|
+
def allow(*ids)
|
107
107
|
@allowed += Array(ids).flatten
|
108
108
|
end
|
109
109
|
|
@@ -112,7 +112,7 @@ module Selenium
|
|
112
112
|
# Overrides default #debug to skip ignored messages by provided id
|
113
113
|
#
|
114
114
|
# @param [String] message
|
115
|
-
# @param [Symbol, Array<
|
115
|
+
# @param [Symbol, Array<Symbol>] id
|
116
116
|
# @yield see #deprecate
|
117
117
|
#
|
118
118
|
def debug(message, id: [], &block)
|
@@ -123,7 +123,7 @@ module Selenium
|
|
123
123
|
# Used to supply information of general interest
|
124
124
|
#
|
125
125
|
# @param [String] message
|
126
|
-
# @param [Symbol, Array<
|
126
|
+
# @param [Symbol, Array<Symbol>] id
|
127
127
|
# @yield see #deprecate
|
128
128
|
#
|
129
129
|
def info(message, id: [], &block)
|
@@ -134,7 +134,7 @@ module Selenium
|
|
134
134
|
# Used to supply information that suggests an error occurred
|
135
135
|
#
|
136
136
|
# @param [String] message
|
137
|
-
# @param [Symbol, Array<
|
137
|
+
# @param [Symbol, Array<Symbol>] id
|
138
138
|
# @yield see #deprecate
|
139
139
|
#
|
140
140
|
def error(message, id: [], &block)
|
@@ -145,7 +145,7 @@ module Selenium
|
|
145
145
|
# Used to supply information that suggests action be taken by user
|
146
146
|
#
|
147
147
|
# @param [String] message
|
148
|
-
# @param [Symbol, Array<
|
148
|
+
# @param [Symbol, Array<Symbol>] id
|
149
149
|
# @yield see #deprecate
|
150
150
|
#
|
151
151
|
def warn(message, id: [], &block)
|
@@ -181,11 +181,11 @@ module Selenium
|
|
181
181
|
private
|
182
182
|
|
183
183
|
def create_logger(name, level:)
|
184
|
-
logger = ::Logger.new($
|
184
|
+
logger = ::Logger.new($stderr)
|
185
185
|
logger.progname = name
|
186
186
|
logger.level = level
|
187
187
|
logger.formatter = proc do |severity, time, progname, msg|
|
188
|
-
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
|
188
|
+
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n".force_encoding('UTF-8')
|
189
189
|
end
|
190
190
|
|
191
191
|
logger
|
@@ -24,6 +24,8 @@ module Selenium
|
|
24
24
|
set_window_rect timeouts unhandled_prompt_behavior strict_file_interactability
|
25
25
|
web_socket_url].freeze
|
26
26
|
|
27
|
+
GRID_OPTIONS = %i[enable_downloads].freeze
|
28
|
+
|
27
29
|
class << self
|
28
30
|
attr_reader :driver_path
|
29
31
|
|
@@ -57,7 +59,7 @@ module Selenium
|
|
57
59
|
@options[key]
|
58
60
|
end
|
59
61
|
|
60
|
-
define_method "#{key}=" do |value|
|
62
|
+
define_method :"#{key}=" do |value|
|
61
63
|
@options[key] = value
|
62
64
|
end
|
63
65
|
end
|
@@ -104,6 +106,8 @@ module Selenium
|
|
104
106
|
def as_json(*)
|
105
107
|
options = @options.dup
|
106
108
|
|
109
|
+
downloads = options.delete(:enable_downloads)
|
110
|
+
options['se:downloadsEnabled'] = downloads unless downloads.nil?
|
107
111
|
w3c_options = process_w3c_options(options)
|
108
112
|
|
109
113
|
browser_options = self.class::CAPABILITIES.each_with_object({}) do |(capability_alias, capability_name), hash|
|
@@ -173,7 +177,7 @@ module Selenium
|
|
173
177
|
end
|
174
178
|
|
175
179
|
def camel_case(str)
|
176
|
-
str.gsub(/_([a-z])/) { Regexp.last_match(1)
|
180
|
+
str.gsub(/_([a-z])/) { Regexp.last_match(1)&.upcase }
|
177
181
|
end
|
178
182
|
end # Options
|
179
183
|
end # WebDriver
|
@@ -86,6 +86,10 @@ module Selenium
|
|
86
86
|
os == :linux
|
87
87
|
end
|
88
88
|
|
89
|
+
def unix?
|
90
|
+
os == :unix
|
91
|
+
end
|
92
|
+
|
89
93
|
def wsl?
|
90
94
|
return false unless linux?
|
91
95
|
|
@@ -107,7 +111,9 @@ module Selenium
|
|
107
111
|
windows? && !cygwin? ? %("#{str}") : str
|
108
112
|
end
|
109
113
|
|
110
|
-
def cygwin_path(path, **opts)
|
114
|
+
def cygwin_path(path, only_cygwin: false, **opts)
|
115
|
+
return path if only_cygwin && !cygwin?
|
116
|
+
|
111
117
|
flags = []
|
112
118
|
opts.each { |k, v| flags << "--#{k}" if v }
|
113
119
|
|
@@ -49,7 +49,7 @@ module Selenium
|
|
49
49
|
proxy = new
|
50
50
|
|
51
51
|
ALLOWED.each do |k, v|
|
52
|
-
proxy.send("#{k}=", data[v]) if data.key?(v)
|
52
|
+
proxy.send(:"#{k}=", data[v]) if data.key?(v)
|
53
53
|
end
|
54
54
|
|
55
55
|
proxy
|
@@ -60,7 +60,7 @@ module Selenium
|
|
60
60
|
|
61
61
|
opts.each do |k, v|
|
62
62
|
if ALLOWED.key?(k)
|
63
|
-
send("#{k}=", v)
|
63
|
+
send(:"#{k}=", v)
|
64
64
|
else
|
65
65
|
not_allowed << k
|
66
66
|
end
|
@@ -0,0 +1,45 @@
|
|
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 Script
|
23
|
+
def initialize(bridge)
|
24
|
+
@log_handler = BiDi::LogHandler.new(bridge.bidi)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [int] id of the handler
|
28
|
+
def add_console_message_handler(&block)
|
29
|
+
@log_handler.add_message_handler('console', &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [int] id of the handler
|
33
|
+
def add_javascript_error_handler(&block)
|
34
|
+
@log_handler.add_message_handler('javascript', &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [int] id of the handler previously added
|
38
|
+
def remove_console_message_handler(id)
|
39
|
+
@log_handler.remove_message_handler(id)
|
40
|
+
end
|
41
|
+
|
42
|
+
alias remove_javascript_error_handler remove_console_message_handler
|
43
|
+
end # Script
|
44
|
+
end # WebDriver
|
45
|
+
end # Selenium
|
@@ -35,6 +35,14 @@ module Selenium
|
|
35
35
|
xpath: 'xpath'
|
36
36
|
}.freeze
|
37
37
|
|
38
|
+
class << self
|
39
|
+
attr_accessor :extra_finders
|
40
|
+
|
41
|
+
def finders
|
42
|
+
FINDERS.merge(extra_finders || {})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
38
46
|
#
|
39
47
|
# Find the first element matching the given arguments
|
40
48
|
#
|
@@ -57,7 +65,7 @@ module Selenium
|
|
57
65
|
def find_element(*args)
|
58
66
|
how, what = extract_args(args)
|
59
67
|
|
60
|
-
by =
|
68
|
+
by = SearchContext.finders[how.to_sym]
|
61
69
|
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
62
70
|
|
63
71
|
bridge.find_element_by by, what, ref
|
@@ -72,7 +80,7 @@ module Selenium
|
|
72
80
|
def find_elements(*args)
|
73
81
|
how, what = extract_args(args)
|
74
82
|
|
75
|
-
by =
|
83
|
+
by = SearchContext.finders[how.to_sym]
|
76
84
|
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
77
85
|
|
78
86
|
bridge.find_elements_by by, what, ref
|
@@ -34,76 +34,33 @@ module Selenium
|
|
34
34
|
@bin_path ||= '../../../../../bin'
|
35
35
|
end
|
36
36
|
|
37
|
-
# @param [
|
38
|
-
# @return [
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
driver_path = output['driver_path']
|
46
|
-
Platform.assert_executable driver_path
|
47
|
-
|
48
|
-
if options.respond_to? :binary
|
49
|
-
options.binary = browser_path
|
50
|
-
options.browser_version = nil
|
51
|
-
end
|
52
|
-
|
53
|
-
driver_path
|
37
|
+
# @param [Array] arguments what gets sent to to Selenium Manager binary.
|
38
|
+
# @return [Hash] paths to the requested assets.
|
39
|
+
def binary_paths(*arguments)
|
40
|
+
arguments += %w[--language-binding ruby]
|
41
|
+
arguments += %w[--output json]
|
42
|
+
arguments << '--debug' if WebDriver.logger.debug?
|
43
|
+
|
44
|
+
run(binary, *arguments)
|
54
45
|
end
|
55
46
|
|
56
47
|
private
|
57
48
|
|
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
49
|
# @return [String] the path to the correct selenium manager
|
76
50
|
def binary
|
77
51
|
@binary ||= begin
|
78
|
-
|
79
|
-
|
80
|
-
'/windows/selenium-manager.exe'
|
81
|
-
elsif Platform.mac?
|
82
|
-
'/macos/selenium-manager'
|
83
|
-
elsif Platform.linux?
|
84
|
-
'/linux/selenium-manager'
|
85
|
-
end
|
86
|
-
location = File.expand_path(path, __FILE__)
|
87
|
-
|
88
|
-
begin
|
89
|
-
Platform.assert_file(location)
|
90
|
-
Platform.assert_executable(location)
|
91
|
-
rescue TypeError
|
92
|
-
raise Error::WebDriverError,
|
93
|
-
"Unable to locate or obtain Selenium Manager binary; #{location} is not a valid file object"
|
94
|
-
rescue Error::WebDriverError => e
|
95
|
-
raise Error::WebDriverError, "Selenium Manager binary located, but #{e.message}"
|
52
|
+
if (location = ENV.fetch('SE_MANAGER_PATH', nil))
|
53
|
+
WebDriver.logger.debug("Selenium Manager set by ENV['SE_MANAGER_PATH']: #{location}")
|
96
54
|
end
|
55
|
+
location ||= platform_location
|
97
56
|
|
57
|
+
Platform.assert_executable(location)
|
98
58
|
WebDriver.logger.debug("Selenium Manager binary found at #{location}", id: :selenium_manager)
|
99
59
|
location
|
100
60
|
end
|
101
61
|
end
|
102
62
|
|
103
63
|
def run(*command)
|
104
|
-
command += %w[--output json]
|
105
|
-
command << '--debug' if WebDriver.logger.debug?
|
106
|
-
|
107
64
|
WebDriver.logger.debug("Executing Process #{command}", id: :selenium_manager)
|
108
65
|
|
109
66
|
begin
|
@@ -112,16 +69,34 @@ module Selenium
|
|
112
69
|
raise Error::WebDriverError, "Unsuccessful command executed: #{command}; #{e.message}"
|
113
70
|
end
|
114
71
|
|
115
|
-
json_output = stdout.empty? ? {} : JSON.parse(stdout)
|
116
|
-
|
72
|
+
json_output = stdout.empty? ? {'logs' => [], 'result' => {}} : JSON.parse(stdout)
|
73
|
+
json_output['logs'].each do |log|
|
117
74
|
level = log['level'].casecmp('info').zero? ? 'debug' : log['level'].downcase
|
118
75
|
WebDriver.logger.send(level, log['message'], id: :selenium_manager)
|
119
76
|
end
|
120
77
|
|
121
78
|
result = json_output['result']
|
122
|
-
return result unless status.exitstatus.positive?
|
79
|
+
return result unless status.exitstatus.positive? || result.nil?
|
123
80
|
|
124
|
-
raise Error::WebDriverError,
|
81
|
+
raise Error::WebDriverError,
|
82
|
+
"Unsuccessful command executed: #{command} - Code #{status.exitstatus}\n#{result}\n#{stderr}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def platform_location
|
86
|
+
directory = File.expand_path(bin_path, __FILE__)
|
87
|
+
if Platform.windows?
|
88
|
+
"#{directory}/windows/selenium-manager.exe"
|
89
|
+
elsif Platform.mac?
|
90
|
+
"#{directory}/macos/selenium-manager"
|
91
|
+
elsif Platform.linux?
|
92
|
+
"#{directory}/linux/selenium-manager"
|
93
|
+
elsif Platform.unix?
|
94
|
+
WebDriver.logger.warn('Selenium Manager binary may not be compatible with Unix',
|
95
|
+
id: %i[selenium_manager unix_binary])
|
96
|
+
"#{directory}/linux/selenium-manager"
|
97
|
+
else
|
98
|
+
raise Error::WebDriverError, "unsupported platform: #{Platform.os}"
|
99
|
+
end
|
125
100
|
end
|
126
101
|
end
|
127
102
|
end # SeleniumManager
|
@@ -87,6 +87,10 @@ module Selenium
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def launch
|
90
|
+
@executable_path ||= begin
|
91
|
+
default_options = WebDriver.const_get("#{self.class.name&.split('::')&.[](2)}::Options").new
|
92
|
+
DriverFinder.new(default_options, self).driver_path
|
93
|
+
end
|
90
94
|
ServiceManager.new(self).tap(&:start)
|
91
95
|
end
|
92
96
|
|
@@ -40,8 +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.args
|
44
43
|
@io = config.log
|
44
|
+
@extra_args = config.args
|
45
45
|
@shutdown_supported = config.shutdown_supported
|
46
46
|
|
47
47
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
@@ -78,7 +78,7 @@ module Selenium
|
|
78
78
|
def listening?
|
79
79
|
addr = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
|
80
80
|
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
81
|
-
sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
|
81
|
+
sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3].to_s)
|
82
82
|
|
83
83
|
begin
|
84
84
|
sock.connect_nonblock sockaddr
|
@@ -49,6 +49,10 @@ module Selenium
|
|
49
49
|
# @api public
|
50
50
|
|
51
51
|
def screenshot_as(format, full_page: false)
|
52
|
+
if full_page && !respond_to?(:save_full_page_screenshot)
|
53
|
+
raise Error::UnsupportedOperationError, "Full Page Screenshots are not supported for #{inspect}"
|
54
|
+
end
|
55
|
+
|
52
56
|
case format
|
53
57
|
when :base64
|
54
58
|
full_page ? full_screenshot : screenshot
|
@@ -57,8 +61,6 @@ module Selenium
|
|
57
61
|
else
|
58
62
|
raise Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
|
59
63
|
end
|
60
|
-
rescue NameError
|
61
|
-
raise Error::UnsupportedOperationError, "Full Page Screenshots are not supported for #{inspect}"
|
62
64
|
end
|
63
65
|
end # TakesScreenshot
|
64
66
|
end # WebDriver
|
@@ -52,6 +52,18 @@ module Selenium
|
|
52
52
|
@callbacks ||= Hash.new { |callbacks, event| callbacks[event] = [] }
|
53
53
|
end
|
54
54
|
|
55
|
+
def add_callback(event, &block)
|
56
|
+
callbacks[event] << block
|
57
|
+
block.object_id
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_callback(event, id)
|
61
|
+
return if callbacks[event].reject! { |callback| callback.object_id == id }
|
62
|
+
|
63
|
+
ids = callbacks[event]&.map(&:object_id)
|
64
|
+
raise Error::WebDriverError, "Callback with ID #{id} does not exist for event #{event}: #{ids}"
|
65
|
+
end
|
66
|
+
|
55
67
|
def send_cmd(**payload)
|
56
68
|
id = next_id
|
57
69
|
data = payload.merge(id: id)
|
@@ -68,10 +68,8 @@ require 'selenium/webdriver/common/html5/local_storage'
|
|
68
68
|
require 'selenium/webdriver/common/html5/session_storage'
|
69
69
|
require 'selenium/webdriver/common/driver_extensions/has_web_storage'
|
70
70
|
require 'selenium/webdriver/common/driver_extensions/downloads_files'
|
71
|
-
require 'selenium/webdriver/common/driver_extensions/has_location'
|
72
71
|
require 'selenium/webdriver/common/driver_extensions/has_session_id'
|
73
72
|
require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
|
74
|
-
require 'selenium/webdriver/common/driver_extensions/has_network_connection'
|
75
73
|
require 'selenium/webdriver/common/driver_extensions/has_network_interception'
|
76
74
|
require 'selenium/webdriver/common/driver_extensions/has_apple_permissions'
|
77
75
|
require 'selenium/webdriver/common/driver_extensions/has_permissions'
|
@@ -83,6 +81,7 @@ require 'selenium/webdriver/common/driver_extensions/full_page_screenshot'
|
|
83
81
|
require 'selenium/webdriver/common/driver_extensions/has_addons'
|
84
82
|
require 'selenium/webdriver/common/driver_extensions/has_bidi'
|
85
83
|
require 'selenium/webdriver/common/driver_extensions/has_devtools'
|
84
|
+
require 'selenium/webdriver/common/driver_extensions/has_file_downloads'
|
86
85
|
require 'selenium/webdriver/common/driver_extensions/has_authentication'
|
87
86
|
require 'selenium/webdriver/common/driver_extensions/has_logs'
|
88
87
|
require 'selenium/webdriver/common/driver_extensions/has_log_events'
|
@@ -90,6 +89,7 @@ require 'selenium/webdriver/common/driver_extensions/has_pinned_scripts'
|
|
90
89
|
require 'selenium/webdriver/common/driver_extensions/has_cdp'
|
91
90
|
require 'selenium/webdriver/common/driver_extensions/has_casting'
|
92
91
|
require 'selenium/webdriver/common/driver_extensions/has_launching'
|
92
|
+
require 'selenium/webdriver/common/driver_extensions/has_fedcm_dialog'
|
93
93
|
require 'selenium/webdriver/common/keys'
|
94
94
|
require 'selenium/webdriver/common/profile_helper'
|
95
95
|
require 'selenium/webdriver/common/options'
|
@@ -99,3 +99,6 @@ require 'selenium/webdriver/common/element'
|
|
99
99
|
require 'selenium/webdriver/common/shadow_root'
|
100
100
|
require 'selenium/webdriver/common/websocket_connection'
|
101
101
|
require 'selenium/webdriver/common/child_process'
|
102
|
+
require 'selenium/webdriver/common/script'
|
103
|
+
require 'selenium/webdriver/common/fedcm/account'
|
104
|
+
require 'selenium/webdriver/common/fedcm/dialog'
|
@@ -98,7 +98,7 @@ module Selenium
|
|
98
98
|
original = DevTools::Request.from(id, params)
|
99
99
|
mutable = DevTools::Request.from(id, params)
|
100
100
|
|
101
|
-
block.call(mutable) do |&continue|
|
101
|
+
block.call(mutable) do |&continue|
|
102
102
|
pending_response_requests[id] = continue
|
103
103
|
|
104
104
|
if original == mutable
|
@@ -35,8 +35,12 @@ module Selenium
|
|
35
35
|
send_command: [:post, 'session/:session_id/ms/cdp/execute']
|
36
36
|
}.freeze
|
37
37
|
|
38
|
+
def command_list
|
39
|
+
EDGE_COMMANDS.merge(CHROMIUM_COMMANDS).merge(self.class::COMMANDS)
|
40
|
+
end
|
41
|
+
|
38
42
|
def commands(command)
|
39
|
-
|
43
|
+
command_list[command]
|
40
44
|
end
|
41
45
|
end # Bridge
|
42
46
|
end # Edge
|
@@ -24,6 +24,13 @@ module Selenium
|
|
24
24
|
DEFAULT_PORT = 9515
|
25
25
|
EXECUTABLE = 'msedgedriver'
|
26
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
|
27
34
|
end # Service
|
28
35
|
end # Edge
|
29
36
|
end # WebDriver
|
@@ -29,8 +29,12 @@ module Selenium
|
|
29
29
|
full_page_screenshot: [:get, 'session/:session_id/moz/screenshot/full']
|
30
30
|
}.freeze
|
31
31
|
|
32
|
+
def command_list
|
33
|
+
FIREFOX_COMMANDS.merge(self.class::COMMANDS)
|
34
|
+
end
|
35
|
+
|
32
36
|
def commands(command)
|
33
|
-
|
37
|
+
command_list[command]
|
34
38
|
end
|
35
39
|
|
36
40
|
def install_addon(path, temporary)
|
@@ -64,6 +64,9 @@ module Selenium
|
|
64
64
|
|
65
65
|
@options[:args] ||= []
|
66
66
|
@options[:prefs] ||= {}
|
67
|
+
# Firefox 129 onwards the CDP protocol will not be enabled by default. Setting this preference will enable it.
|
68
|
+
# https://fxdx.dev/deprecating-cdp-support-in-firefox-embracing-the-future-with-webdriver-bidi/.
|
69
|
+
@options[:prefs]['remote.active-protocols'] = 3
|
67
70
|
@options[:env] ||= {}
|
68
71
|
@options[:log] ||= {level: log_level} if log_level
|
69
72
|
|
@@ -24,6 +24,10 @@ module Selenium
|
|
24
24
|
include ProfileHelper
|
25
25
|
|
26
26
|
VALID_PREFERENCE_TYPES = [TrueClass, FalseClass, Integer, Float, String].freeze
|
27
|
+
WEBDRIVER_PREFS = {
|
28
|
+
port: 'webdriver_firefox_port',
|
29
|
+
log_file: 'webdriver.log.file'
|
30
|
+
}.freeze
|
27
31
|
|
28
32
|
DEFAULT_PREFERENCES = {
|
29
33
|
'browser.newtabpage.enabled' => false,
|
@@ -33,8 +37,10 @@ module Selenium
|
|
33
37
|
'security.csp.enable' => false
|
34
38
|
}.freeze
|
35
39
|
|
36
|
-
|
37
|
-
|
40
|
+
LOCK_FILES = %w[.parentlock parent.lock lock].freeze
|
41
|
+
|
42
|
+
attr_reader :name, :log_file
|
43
|
+
attr_writer :secure_ssl, :load_no_focus_lib
|
38
44
|
|
39
45
|
class << self
|
40
46
|
def ini
|
@@ -176,7 +182,7 @@ module Selenium
|
|
176
182
|
end
|
177
183
|
|
178
184
|
def delete_lock_files(directory)
|
179
|
-
|
185
|
+
LOCK_FILES.each do |name|
|
180
186
|
FileUtils.rm_f File.join(directory, name)
|
181
187
|
end
|
182
188
|
end
|
@@ -204,8 +210,8 @@ module Selenium
|
|
204
210
|
File.read(path).split("\n").each do |line|
|
205
211
|
next unless line =~ /user_pref\("([^"]+)"\s*,\s*(.+?)\);/
|
206
212
|
|
207
|
-
key = Regexp.last_match(1)
|
208
|
-
value = Regexp.last_match(2)
|
213
|
+
key = Regexp.last_match(1)&.strip
|
214
|
+
value = Regexp.last_match(2)&.strip
|
209
215
|
|
210
216
|
# wrap the value in an array to make it a valid JSON string.
|
211
217
|
prefs[key] = JSON.parse("[#{value}]").first
|
@@ -221,7 +227,9 @@ module Selenium
|
|
221
227
|
end
|
222
228
|
end
|
223
229
|
end
|
224
|
-
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Profile
|
225
233
|
end # Firefox
|
226
234
|
end # WebDriver
|
227
235
|
end # Selenium
|
@@ -52,7 +52,7 @@ module Selenium
|
|
52
52
|
when /^\[Profile/
|
53
53
|
name, path = nil if path_for(name, is_relative, path)
|
54
54
|
when /^Name=(.+)$/
|
55
|
-
name = Regexp.last_match(1)
|
55
|
+
name = Regexp.last_match(1)&.strip
|
56
56
|
when /^IsRelative=(.+)$/
|
57
57
|
is_relative = Regexp.last_match(1).strip == '1'
|
58
58
|
when /^Path=(.+)$/
|
@@ -17,20 +17,18 @@
|
|
17
17
|
# specific language governing permissions and limitations
|
18
18
|
# under the License.
|
19
19
|
|
20
|
-
# TODO: Deprecated; Delete after 4.0 release
|
21
20
|
module Selenium
|
22
21
|
module WebDriver
|
23
|
-
module
|
24
|
-
module
|
25
|
-
def
|
26
|
-
|
22
|
+
module IE
|
23
|
+
module Features
|
24
|
+
def command_list
|
25
|
+
self.class::COMMANDS
|
27
26
|
end
|
28
27
|
|
29
|
-
def
|
30
|
-
|
28
|
+
def commands(command)
|
29
|
+
command_list[command]
|
31
30
|
end
|
32
|
-
|
33
|
-
|
34
|
-
end # DriverExtensions
|
31
|
+
end # Bridge
|
32
|
+
end # Ie
|
35
33
|
end # WebDriver
|
36
34
|
end # Selenium
|
@@ -42,7 +42,8 @@ module Selenium
|
|
42
42
|
use_legacy_file_upload_dialog_handling: 'ie.useLegacyFileUploadDialogHandling',
|
43
43
|
attach_to_edge_chrome: 'ie.edgechromium',
|
44
44
|
edge_executable_path: 'ie.edgepath',
|
45
|
-
ignore_process_match: 'ie.ignoreprocessmatch'
|
45
|
+
ignore_process_match: 'ie.ignoreprocessmatch',
|
46
|
+
silent: 'silent'
|
46
47
|
}.freeze
|
47
48
|
BROWSER = 'internet explorer'
|
48
49
|
|
@@ -81,7 +82,7 @@ module Selenium
|
|
81
82
|
|
82
83
|
def initialize(**opts)
|
83
84
|
@args = (opts.delete(:args) || []).to_set
|
84
|
-
super
|
85
|
+
super
|
85
86
|
|
86
87
|
@options[:native_events] = true if @options[:native_events].nil?
|
87
88
|
end
|
@@ -20,9 +20,10 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
module IE
|
23
|
-
autoload :
|
24
|
-
autoload :
|
25
|
-
autoload :
|
23
|
+
autoload :Features, 'selenium/webdriver/ie/features'
|
24
|
+
autoload :Driver, 'selenium/webdriver/ie/driver'
|
25
|
+
autoload :Options, 'selenium/webdriver/ie/options'
|
26
|
+
autoload :Service, 'selenium/webdriver/ie/service'
|
26
27
|
end # IE
|
27
28
|
end # WebDriver
|
28
29
|
end # Selenium
|