selenium-webdriver 4.5.0 → 4.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -27,15 +27,17 @@ module Selenium
|
|
27
27
|
#
|
28
28
|
|
29
29
|
class Scroll < Interaction
|
30
|
-
def initialize(source:,
|
30
|
+
def initialize(source:, origin: :viewport, duration: 0.25, **opts)
|
31
31
|
super(source)
|
32
32
|
@type = :scroll
|
33
33
|
@duration = duration * 1000
|
34
34
|
@origin = origin
|
35
|
-
@x_offset = x
|
36
|
-
@y_offset = y
|
37
|
-
@delta_x = delta_x
|
38
|
-
@delta_y = delta_y
|
35
|
+
@x_offset = opts.delete(:x) || 0
|
36
|
+
@y_offset = opts.delete(:y) || 0
|
37
|
+
@delta_x = opts.delete(:delta_x) || 0
|
38
|
+
@delta_y = opts.delete(:delta_y) || 0
|
39
|
+
|
40
|
+
raise ArgumentError, "Invalid arguments: #{opts.keys}" unless opts.empty?
|
39
41
|
end
|
40
42
|
|
41
43
|
def assert_source(source)
|
@@ -0,0 +1,46 @@
|
|
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
|
+
module LocalDriver
|
23
|
+
def initialize_local_driver(options, service, url)
|
24
|
+
raise ArgumentError, "Can't initialize #{self.class} with :url" if url
|
25
|
+
|
26
|
+
service ||= Service.send(browser)
|
27
|
+
caps = process_options(options, service)
|
28
|
+
url = service_url(service)
|
29
|
+
|
30
|
+
[caps, url]
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_options(options, service)
|
34
|
+
default_options = Options.send(browser)
|
35
|
+
options ||= default_options
|
36
|
+
|
37
|
+
unless options.is_a?(default_options.class)
|
38
|
+
raise ArgumentError, ":options must be an instance of #{default_options.class}"
|
39
|
+
end
|
40
|
+
|
41
|
+
service.executable_path ||= WebDriver::DriverFinder.path(options, service.class)
|
42
|
+
options.as_json
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -38,19 +38,31 @@ module Selenium
|
|
38
38
|
|
39
39
|
def_delegators :@logger,
|
40
40
|
:close,
|
41
|
-
:debug
|
42
|
-
:info
|
41
|
+
:debug?,
|
42
|
+
:info?,
|
43
43
|
:warn?,
|
44
|
-
:error
|
44
|
+
:error?,
|
45
45
|
:fatal, :fatal?,
|
46
|
-
:level
|
46
|
+
:level
|
47
47
|
|
48
48
|
#
|
49
49
|
# @param [String] progname Allow child projects to use Selenium's Logger pattern
|
50
50
|
#
|
51
|
-
def initialize(progname = 'Selenium')
|
52
|
-
|
53
|
-
|
51
|
+
def initialize(progname = 'Selenium', default_level: nil, ignored: nil, allowed: nil)
|
52
|
+
default_level ||= $DEBUG || ENV.key?('DEBUG') ? :debug : :warn
|
53
|
+
|
54
|
+
@logger = create_logger(progname, level: default_level)
|
55
|
+
@ignored = Array(ignored)
|
56
|
+
@allowed = Array(allowed)
|
57
|
+
@first_warning = false
|
58
|
+
end
|
59
|
+
|
60
|
+
def level=(level)
|
61
|
+
if level == :info && @logger.level == :info
|
62
|
+
info(':info is now the default log level, to see additional logging, set log level to :debug')
|
63
|
+
end
|
64
|
+
|
65
|
+
@logger.level = level
|
54
66
|
end
|
55
67
|
|
56
68
|
#
|
@@ -80,27 +92,64 @@ module Selenium
|
|
80
92
|
#
|
81
93
|
# Will not log the provided ID.
|
82
94
|
#
|
83
|
-
# @param [Array, Symbol]
|
95
|
+
# @param [Array, Symbol] ids
|
96
|
+
#
|
97
|
+
def ignore(*ids)
|
98
|
+
@ignored += Array(ids).flatten
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Will only log the provided ID.
|
84
103
|
#
|
85
|
-
|
86
|
-
|
104
|
+
# @param [Array, Symbol] ids
|
105
|
+
#
|
106
|
+
def allow(*ids)
|
107
|
+
@allowed += Array(ids).flatten
|
87
108
|
end
|
88
109
|
|
89
110
|
#
|
90
|
-
#
|
111
|
+
# Used to supply information of interest for debugging a problem
|
112
|
+
# Overrides default #debug to skip ignored messages by provided id
|
91
113
|
#
|
92
114
|
# @param [String] message
|
93
|
-
# @param [Symbol, Array<
|
115
|
+
# @param [Symbol, Array<Symbol>] id
|
94
116
|
# @yield see #deprecate
|
95
117
|
#
|
96
|
-
def
|
97
|
-
|
98
|
-
|
118
|
+
def debug(message, id: [], &block)
|
119
|
+
discard_or_log(:debug, message, id, &block)
|
120
|
+
end
|
99
121
|
|
100
|
-
|
101
|
-
|
122
|
+
#
|
123
|
+
# Used to supply information of general interest
|
124
|
+
#
|
125
|
+
# @param [String] message
|
126
|
+
# @param [Symbol, Array<Symbol>] id
|
127
|
+
# @yield see #deprecate
|
128
|
+
#
|
129
|
+
def info(message, id: [], &block)
|
130
|
+
discard_or_log(:info, message, id, &block)
|
131
|
+
end
|
102
132
|
|
103
|
-
|
133
|
+
#
|
134
|
+
# Used to supply information that suggests an error occurred
|
135
|
+
#
|
136
|
+
# @param [String] message
|
137
|
+
# @param [Symbol, Array<Symbol>] id
|
138
|
+
# @yield see #deprecate
|
139
|
+
#
|
140
|
+
def error(message, id: [], &block)
|
141
|
+
discard_or_log(:error, message, id, &block)
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Used to supply information that suggests action be taken by user
|
146
|
+
#
|
147
|
+
# @param [String] message
|
148
|
+
# @param [Symbol, Array<Symbol>] id
|
149
|
+
# @yield see #deprecate
|
150
|
+
#
|
151
|
+
def warn(message, id: [], &block)
|
152
|
+
discard_or_log(:warn, message, id, &block)
|
104
153
|
end
|
105
154
|
|
106
155
|
#
|
@@ -114,11 +163,11 @@ module Selenium
|
|
114
163
|
#
|
115
164
|
def deprecate(old, new = nil, id: [], reference: '', &block)
|
116
165
|
id = Array(id)
|
117
|
-
return if @ignored.include?(:deprecations)
|
166
|
+
return if @ignored.include?(:deprecations)
|
118
167
|
|
119
|
-
|
168
|
+
id << :deprecations if @allowed.include?(:deprecations)
|
120
169
|
|
121
|
-
message = +"[DEPRECATION] #{
|
170
|
+
message = +"[DEPRECATION] #{old} is deprecated"
|
122
171
|
message << if new
|
123
172
|
". Use #{new} instead."
|
124
173
|
else
|
@@ -126,15 +175,15 @@ module Selenium
|
|
126
175
|
end
|
127
176
|
message << " See explanation for this deprecation: #{reference}." unless reference.empty?
|
128
177
|
|
129
|
-
warn message, &block
|
178
|
+
discard_or_log(:warn, message, id, &block)
|
130
179
|
end
|
131
180
|
|
132
181
|
private
|
133
182
|
|
134
|
-
def create_logger(name)
|
183
|
+
def create_logger(name, level:)
|
135
184
|
logger = ::Logger.new($stdout)
|
136
185
|
logger.progname = name
|
137
|
-
logger.level =
|
186
|
+
logger.level = level
|
138
187
|
logger.formatter = proc do |severity, time, progname, msg|
|
139
188
|
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
|
140
189
|
end
|
@@ -142,8 +191,24 @@ module Selenium
|
|
142
191
|
logger
|
143
192
|
end
|
144
193
|
|
145
|
-
def
|
146
|
-
|
194
|
+
def discard_or_log(level, message, id)
|
195
|
+
id = Array(id)
|
196
|
+
return if (@ignored & id).any?
|
197
|
+
return if @allowed.any? && (@allowed & id).none?
|
198
|
+
|
199
|
+
return if ::Logger::Severity.const_get(level.upcase) < @logger.level
|
200
|
+
|
201
|
+
unless @first_warning
|
202
|
+
@first_warning = true
|
203
|
+
info("Details on how to use and modify Selenium logger:\n", id: [:logger_info]) do
|
204
|
+
"https://selenium.dev/documentation/webdriver/troubleshooting/logging\n"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
msg = id.empty? ? message : "[#{id.map(&:inspect).join(', ')}] #{message} "
|
209
|
+
msg += " #{yield}" if block_given?
|
210
|
+
|
211
|
+
@logger.send(level) { msg }
|
147
212
|
end
|
148
213
|
end # Logger
|
149
214
|
end # WebDriver
|
@@ -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
|
|
@@ -38,12 +40,12 @@ module Selenium
|
|
38
40
|
def ie(**opts)
|
39
41
|
IE::Options.new(**opts)
|
40
42
|
end
|
41
|
-
|
43
|
+
alias internet_explorer ie
|
42
44
|
|
43
45
|
def edge(**opts)
|
44
46
|
Edge::Options.new(**opts)
|
45
47
|
end
|
46
|
-
|
48
|
+
alias microsoftedge edge
|
47
49
|
|
48
50
|
def safari(**opts)
|
49
51
|
Safari::Options.new(**opts)
|
@@ -85,7 +87,7 @@ module Selenium
|
|
85
87
|
#
|
86
88
|
|
87
89
|
def add_option(name, value = nil)
|
88
|
-
|
90
|
+
name, value = name.first if value.nil? && name.is_a?(Hash)
|
89
91
|
@options[name] = value
|
90
92
|
end
|
91
93
|
|
@@ -95,7 +97,7 @@ module Selenium
|
|
95
97
|
as_json == other.as_json
|
96
98
|
end
|
97
99
|
|
98
|
-
|
100
|
+
alias eql? ==
|
99
101
|
|
100
102
|
#
|
101
103
|
# @api private
|
@@ -104,13 +106,18 @@ 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
|
-
self.class::CAPABILITIES.
|
113
|
+
browser_options = self.class::CAPABILITIES.each_with_object({}) do |(capability_alias, capability_name), hash|
|
110
114
|
capability_value = options.delete(capability_alias)
|
111
|
-
|
115
|
+
hash[capability_name] = capability_value unless capability_value.nil?
|
112
116
|
end
|
113
|
-
|
117
|
+
|
118
|
+
raise Error::WebDriverError, "These options are not w3c compliant: #{options}" unless options.empty?
|
119
|
+
|
120
|
+
browser_options = {self.class::KEY => browser_options} if defined?(self.class::KEY)
|
114
121
|
|
115
122
|
process_browser_options(browser_options)
|
116
123
|
generate_as_json(w3c_options.merge(browser_options))
|
@@ -123,7 +130,7 @@ module Selenium
|
|
123
130
|
end
|
124
131
|
|
125
132
|
def process_w3c_options(options)
|
126
|
-
w3c_options = options.select { |key,
|
133
|
+
w3c_options = options.select { |key, val| w3c?(key) && !val.nil? }
|
127
134
|
w3c_options[:unhandled_prompt_behavior] &&= w3c_options[:unhandled_prompt_behavior]&.to_s&.tr('_', ' ')
|
128
135
|
options.delete_if { |key, _val| w3c?(key) }
|
129
136
|
w3c_options
|
@@ -62,22 +62,14 @@ module Selenium
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def bitsize
|
66
|
-
@bitsize ||= if defined?(FFI::Platform::ADDRESS_SIZE)
|
67
|
-
FFI::Platform::ADDRESS_SIZE
|
68
|
-
elsif defined?(FFI)
|
69
|
-
FFI.type_size(:pointer) == 4 ? 32 : 64
|
70
|
-
elsif jruby?
|
71
|
-
Integer(ENV_JAVA['sun.arch.data.model'])
|
72
|
-
else
|
73
|
-
1.size == 4 ? 32 : 64
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
65
|
def jruby?
|
78
66
|
engine == :jruby
|
79
67
|
end
|
80
68
|
|
69
|
+
def truffleruby?
|
70
|
+
engine == :truffleruby
|
71
|
+
end
|
72
|
+
|
81
73
|
def ruby_version
|
82
74
|
RUBY_VERSION
|
83
75
|
end
|
@@ -94,6 +86,10 @@ module Selenium
|
|
94
86
|
os == :linux
|
95
87
|
end
|
96
88
|
|
89
|
+
def unix?
|
90
|
+
os == :unix
|
91
|
+
end
|
92
|
+
|
97
93
|
def wsl?
|
98
94
|
return false unless linux?
|
99
95
|
|
@@ -154,43 +150,6 @@ module Selenium
|
|
154
150
|
at_exit { yield if Process.pid == pid }
|
155
151
|
end
|
156
152
|
|
157
|
-
def find_binary(*binary_names)
|
158
|
-
paths = ENV['PATH'].split(File::PATH_SEPARATOR)
|
159
|
-
|
160
|
-
if windows?
|
161
|
-
binary_names.map! { |n| "#{n}.exe" }
|
162
|
-
binary_names.dup.each { |n| binary_names << n.gsub('exe', 'bat') }
|
163
|
-
end
|
164
|
-
|
165
|
-
binary_names.each do |binary_name|
|
166
|
-
paths.each do |path|
|
167
|
-
full_path = File.join(path, binary_name)
|
168
|
-
full_path = unix_path(full_path) if windows?
|
169
|
-
exe = Dir.glob(full_path).find { |f| File.executable?(f) }
|
170
|
-
return exe if exe
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
nil
|
175
|
-
end
|
176
|
-
|
177
|
-
def find_in_program_files(*binary_names)
|
178
|
-
paths = [
|
179
|
-
ENV.fetch('PROGRAMFILES', '\\Program Files'),
|
180
|
-
ENV.fetch('ProgramFiles(x86)', '\\Program Files (x86)'),
|
181
|
-
ENV.fetch('ProgramW6432', '\\Program Files')
|
182
|
-
]
|
183
|
-
|
184
|
-
paths.each do |root|
|
185
|
-
binary_names.each do |name|
|
186
|
-
exe = File.join(root, name)
|
187
|
-
return exe if File.executable?(exe)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
nil
|
192
|
-
end
|
193
|
-
|
194
153
|
def localhost
|
195
154
|
info = Socket.getaddrinfo 'localhost', 80, Socket::AF_INET, Socket::SOCK_STREAM
|
196
155
|
|
@@ -34,7 +34,7 @@ module Selenium
|
|
34
34
|
Platform.interfaces.each do |host|
|
35
35
|
TCPServer.new(host, port).close
|
36
36
|
rescue *IGNORED_ERRORS => e
|
37
|
-
WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
|
37
|
+
WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})", id: :driver_service)
|
38
38
|
# ignored - some machines appear unable to bind to some of their interfaces
|
39
39
|
end
|
40
40
|
|
@@ -74,7 +74,7 @@ module Selenium
|
|
74
74
|
def ==(other)
|
75
75
|
other.is_a?(self.class) && as_json == other.as_json
|
76
76
|
end
|
77
|
-
|
77
|
+
alias eql? ==
|
78
78
|
|
79
79
|
def ftp=(value)
|
80
80
|
self.type = :manual
|
@@ -152,7 +152,7 @@ module Selenium
|
|
152
152
|
'socksUsername' => socks_username,
|
153
153
|
'socksPassword' => socks_password,
|
154
154
|
'socksVersion' => socks_version
|
155
|
-
}.
|
155
|
+
}.compact
|
156
156
|
|
157
157
|
json_result if json_result.length > 1
|
158
158
|
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed to the Software Freedom Conservancy (SFC) under one
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
5
|
+
# distributed with this work for additional information
|
6
|
+
# regarding copyright ownership. The SFC licenses this file
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance
|
9
|
+
# with the License. You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
14
|
+
# software distributed under the License is distributed on an
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
16
|
+
# KIND, either express or implied. See the License for the
|
17
|
+
# specific language governing permissions and limitations
|
18
|
+
# under the License.
|
19
|
+
|
20
|
+
require 'open3'
|
21
|
+
|
22
|
+
module Selenium
|
23
|
+
module WebDriver
|
24
|
+
#
|
25
|
+
# Wrapper for getting information from the Selenium Manager binaries.
|
26
|
+
# This implementation is still in beta, and may change.
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
class SeleniumManager
|
30
|
+
class << self
|
31
|
+
attr_writer :bin_path
|
32
|
+
|
33
|
+
def bin_path
|
34
|
+
@bin_path ||= '../../../../../bin'
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [Options] options browser options.
|
38
|
+
# @return [String] the path to the correct driver.
|
39
|
+
def driver_path(options)
|
40
|
+
command = generate_command(binary, options)
|
41
|
+
|
42
|
+
output = run(*command)
|
43
|
+
|
44
|
+
browser_path = Platform.cygwin? ? Platform.cygwin_path(output['browser_path']) : output['browser_path']
|
45
|
+
driver_path = Platform.cygwin? ? Platform.cygwin_path(output['driver_path']) : output['driver_path']
|
46
|
+
Platform.assert_executable driver_path
|
47
|
+
|
48
|
+
if options.respond_to?(:binary) && browser_path && !browser_path.empty?
|
49
|
+
options.binary = browser_path
|
50
|
+
options.browser_version = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
driver_path
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def generate_command(binary, options)
|
59
|
+
command = [binary, '--browser', options.browser_name]
|
60
|
+
if options.browser_version
|
61
|
+
command << '--browser-version'
|
62
|
+
command << options.browser_version
|
63
|
+
end
|
64
|
+
if options.respond_to?(:binary) && !options.binary.nil?
|
65
|
+
command << '--browser-path'
|
66
|
+
command << options.binary.gsub('\\', '\\\\\\')
|
67
|
+
end
|
68
|
+
if options.proxy
|
69
|
+
command << '--proxy'
|
70
|
+
command << (options.proxy.ssl || options.proxy.http)
|
71
|
+
end
|
72
|
+
command
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [String] the path to the correct selenium manager
|
76
|
+
def binary
|
77
|
+
@binary ||= begin
|
78
|
+
location = ENV.fetch('SE_MANAGER_PATH', begin
|
79
|
+
directory = File.expand_path(bin_path, __FILE__)
|
80
|
+
if Platform.windows?
|
81
|
+
"#{directory}/windows/selenium-manager.exe"
|
82
|
+
elsif Platform.mac?
|
83
|
+
"#{directory}/macos/selenium-manager"
|
84
|
+
elsif Platform.linux?
|
85
|
+
"#{directory}/linux/selenium-manager"
|
86
|
+
elsif Platform.unix?
|
87
|
+
WebDriver.logger.warn('Selenium Manager binary may not be compatible with Unix; verify settings',
|
88
|
+
id: %i[selenium_manager unix_binary])
|
89
|
+
"#{directory}/linux/selenium-manager"
|
90
|
+
end
|
91
|
+
rescue Error::WebDriverError => e
|
92
|
+
raise Error::WebDriverError, "Unable to obtain Selenium Manager binary for #{e.message}"
|
93
|
+
end)
|
94
|
+
|
95
|
+
validate_location(location)
|
96
|
+
location
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_location(location)
|
101
|
+
begin
|
102
|
+
Platform.assert_file(location)
|
103
|
+
Platform.assert_executable(location)
|
104
|
+
rescue TypeError
|
105
|
+
raise Error::WebDriverError,
|
106
|
+
"Unable to locate or obtain Selenium Manager binary; #{location} is not a valid file object"
|
107
|
+
rescue Error::WebDriverError => e
|
108
|
+
raise Error::WebDriverError, "Selenium Manager binary located, but #{e.message}"
|
109
|
+
end
|
110
|
+
|
111
|
+
WebDriver.logger.debug("Selenium Manager binary found at #{location}", id: :selenium_manager)
|
112
|
+
end
|
113
|
+
|
114
|
+
def run(*command)
|
115
|
+
command += %w[--output json]
|
116
|
+
command << '--debug' if WebDriver.logger.debug?
|
117
|
+
|
118
|
+
WebDriver.logger.debug("Executing Process #{command}", id: :selenium_manager)
|
119
|
+
|
120
|
+
begin
|
121
|
+
stdout, stderr, status = Open3.capture3(*command)
|
122
|
+
rescue StandardError => e
|
123
|
+
raise Error::WebDriverError, "Unsuccessful command executed: #{command}; #{e.message}"
|
124
|
+
end
|
125
|
+
|
126
|
+
json_output = stdout.empty? ? {} : JSON.parse(stdout)
|
127
|
+
(json_output['logs'] || []).each do |log|
|
128
|
+
level = log['level'].casecmp('info').zero? ? 'debug' : log['level'].downcase
|
129
|
+
WebDriver.logger.send(level, log['message'], id: :selenium_manager)
|
130
|
+
end
|
131
|
+
|
132
|
+
result = json_output['result']
|
133
|
+
return result unless status.exitstatus.positive?
|
134
|
+
|
135
|
+
raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{result}#{stderr}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end # SeleniumManager
|
139
|
+
end # WebDriver
|
140
|
+
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,47 +66,37 @@ module Selenium
|
|
65
66
|
# @api private
|
66
67
|
#
|
67
68
|
|
68
|
-
def initialize(path: nil, port: nil, args: nil)
|
69
|
-
path ||= self.class.driver_path
|
69
|
+
def initialize(path: nil, port: nil, log: nil, args: nil)
|
70
70
|
port ||= self.class::DEFAULT_PORT
|
71
71
|
args ||= []
|
72
72
|
|
73
|
-
@executable_path =
|
73
|
+
@executable_path = path
|
74
74
|
@host = Platform.localhost
|
75
75
|
@port = Integer(port)
|
76
|
-
|
77
|
-
|
76
|
+
@log = case log
|
77
|
+
when :stdout
|
78
|
+
$stdout
|
79
|
+
when :stderr
|
80
|
+
$stderr
|
81
|
+
else
|
82
|
+
log
|
83
|
+
end
|
84
|
+
@args = args
|
78
85
|
|
79
86
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
80
87
|
end
|
81
88
|
|
82
89
|
def launch
|
83
|
-
|
84
|
-
|
85
|
-
|
90
|
+
@executable_path ||= begin
|
91
|
+
default_options = WebDriver.const_get("#{self.class.name.split('::')[2]}::Options").new
|
92
|
+
DriverFinder.path(default_options, self.class)
|
93
|
+
end
|
94
|
+
ServiceManager.new(self).tap(&:start)
|
86
95
|
end
|
87
96
|
|
88
97
|
def shutdown_supported
|
89
98
|
self.class::SHUTDOWN_SUPPORTED
|
90
99
|
end
|
91
|
-
|
92
|
-
protected
|
93
|
-
|
94
|
-
def extract_service_args(driver_opts)
|
95
|
-
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def binary_path(path = nil)
|
101
|
-
path = path.call if path.is_a?(Proc)
|
102
|
-
path ||= Platform.find_binary(self.class::EXECUTABLE)
|
103
|
-
|
104
|
-
raise Error::WebDriverError, self.class::MISSING_TEXT unless path
|
105
|
-
|
106
|
-
Platform.assert_executable path
|
107
|
-
path
|
108
|
-
end
|
109
100
|
end # Service
|
110
101
|
end # WebDriver
|
111
102
|
end # Selenium
|