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
|
@@ -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
|