selenium-webdriver 4.1.0 → 4.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +182 -1
- data/LICENSE +1 -1
- data/NOTICE +1 -1
- data/bin/linux/selenium-manager +0 -0
- data/bin/macos/selenium-manager +0 -0
- data/bin/windows/selenium-manager.exe +0 -0
- data/lib/selenium/server.rb +35 -26
- data/lib/selenium/webdriver/atoms/findElements.js +0 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +0 -0
- data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
- data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
- data/lib/selenium/webdriver/atoms.rb +2 -3
- data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
- data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/filter_by.rb +40 -0
- data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
- data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
- data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
- data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
- data/lib/selenium/webdriver/bidi/session.rb +51 -0
- data/lib/selenium/webdriver/bidi.rb +56 -0
- data/lib/selenium/webdriver/chrome/driver.rb +19 -28
- data/lib/selenium/webdriver/chrome/features.rb +6 -68
- data/lib/selenium/webdriver/chrome/options.rb +3 -223
- data/lib/selenium/webdriver/chrome/profile.rb +3 -83
- data/lib/selenium/webdriver/chrome/service.rb +4 -19
- data/lib/selenium/webdriver/chrome.rb +0 -14
- data/lib/selenium/webdriver/chromium/driver.rb +61 -0
- data/lib/selenium/webdriver/chromium/features.rb +103 -0
- data/lib/selenium/webdriver/chromium/options.rb +261 -0
- data/lib/selenium/webdriver/chromium/profile.rb +113 -0
- data/lib/selenium/webdriver/chromium/service.rb +42 -0
- data/lib/selenium/webdriver/chromium.rb +32 -0
- data/lib/selenium/webdriver/common/action_builder.rb +72 -22
- data/lib/selenium/webdriver/common/child_process.rb +124 -0
- data/lib/selenium/webdriver/common/driver.rb +50 -70
- data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +10 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +1 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -69
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -3
- data/lib/selenium/webdriver/common/element.rb +8 -8
- data/lib/selenium/webdriver/common/error.rb +1 -3
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
- data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
- data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
- data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
- data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
- data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
- data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
- data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
- data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
- data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
- data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
- data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
- data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
- data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
- data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
- data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
- data/lib/selenium/webdriver/common/keys.rb +1 -0
- data/lib/selenium/webdriver/common/logger.rb +10 -2
- data/lib/selenium/webdriver/common/manager.rb +0 -27
- data/lib/selenium/webdriver/common/options.rb +32 -17
- data/lib/selenium/webdriver/common/platform.rb +8 -5
- data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
- data/lib/selenium/webdriver/common/proxy.rb +1 -1
- data/lib/selenium/webdriver/common/search_context.rb +0 -6
- data/lib/selenium/webdriver/common/selenium_manager.rb +89 -0
- data/lib/selenium/webdriver/common/service.rb +16 -8
- data/lib/selenium/webdriver/common/service_manager.rb +4 -13
- data/lib/selenium/webdriver/common/shadow_root.rb +2 -3
- data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
- 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 +85 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
- data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
- data/lib/selenium/webdriver/common/window.rb +6 -6
- data/lib/selenium/webdriver/common/zipper.rb +1 -1
- data/lib/selenium/webdriver/common.rb +19 -3
- data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
- data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
- data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
- data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
- data/lib/selenium/webdriver/devtools/request.rb +1 -3
- data/lib/selenium/webdriver/devtools/response.rb +1 -3
- data/lib/selenium/webdriver/devtools.rb +6 -113
- data/lib/selenium/webdriver/edge/driver.rb +20 -3
- data/lib/selenium/webdriver/edge/features.rb +4 -4
- data/lib/selenium/webdriver/edge/options.rb +3 -5
- data/lib/selenium/webdriver/edge/profile.rb +2 -2
- data/lib/selenium/webdriver/edge/service.rb +2 -2
- data/lib/selenium/webdriver/firefox/driver.rb +20 -2
- data/lib/selenium/webdriver/firefox/features.rb +6 -6
- data/lib/selenium/webdriver/firefox/options.rb +9 -3
- data/lib/selenium/webdriver/firefox/profile.rb +7 -11
- data/lib/selenium/webdriver/firefox/service.rb +0 -1
- data/lib/selenium/webdriver/firefox/util.rb +46 -0
- data/lib/selenium/webdriver/firefox.rb +1 -14
- data/lib/selenium/webdriver/ie/driver.rb +20 -1
- data/lib/selenium/webdriver/ie/service.rb +1 -2
- data/lib/selenium/webdriver/ie.rb +0 -14
- data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +15 -8
- data/lib/selenium/webdriver/remote/bridge.rb +59 -30
- data/lib/selenium/webdriver/remote/capabilities.rb +34 -12
- data/lib/selenium/webdriver/remote/driver.rb +14 -15
- data/lib/selenium/webdriver/remote/http/curb.rb +0 -2
- data/lib/selenium/webdriver/remote/http/default.rb +7 -12
- data/lib/selenium/webdriver/remote/response.rb +2 -3
- data/lib/selenium/webdriver/remote.rb +0 -1
- data/lib/selenium/webdriver/safari/driver.rb +20 -1
- data/lib/selenium/webdriver/safari/features.rb +0 -2
- data/lib/selenium/webdriver/safari/options.rb +5 -1
- data/lib/selenium/webdriver/safari.rb +1 -15
- data/lib/selenium/webdriver/support/color.rb +20 -20
- data/lib/selenium/webdriver/support/guards/guard.rb +0 -2
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -3
- data/lib/selenium/webdriver/support/guards.rb +1 -1
- data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
- data/lib/selenium/webdriver/support/select.rb +3 -1
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +4 -4
- data/selenium-webdriver.gemspec +13 -11
- metadata +68 -59
- data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
|
@@ -0,0 +1,42 @@
|
|
|
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 Interactions
|
|
23
|
+
#
|
|
24
|
+
# Creates actions specific to Pointer Input devices
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
class WheelInput < InputDevice
|
|
30
|
+
def initialize(name = nil)
|
|
31
|
+
super(name)
|
|
32
|
+
@type = Interactions::WHEEL
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def create_scroll(**opts)
|
|
36
|
+
opts[:source] = self
|
|
37
|
+
add_action(Scroll.new(**opts))
|
|
38
|
+
end
|
|
39
|
+
end # PointerInput
|
|
40
|
+
end # Interactions
|
|
41
|
+
end # WebDriver
|
|
42
|
+
end # Selenium
|
|
@@ -48,9 +48,10 @@ module Selenium
|
|
|
48
48
|
#
|
|
49
49
|
# @param [String] progname Allow child projects to use Selenium's Logger pattern
|
|
50
50
|
#
|
|
51
|
-
def initialize(progname = 'Selenium')
|
|
51
|
+
def initialize(progname = 'Selenium', ignored: nil)
|
|
52
52
|
@logger = create_logger(progname)
|
|
53
|
-
@ignored =
|
|
53
|
+
@ignored = Array(ignored)
|
|
54
|
+
@first_warning = false
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
#
|
|
@@ -94,6 +95,13 @@ module Selenium
|
|
|
94
95
|
# @yield see #deprecate
|
|
95
96
|
#
|
|
96
97
|
def warn(message, id: [])
|
|
98
|
+
unless @first_warning
|
|
99
|
+
@first_warning = true
|
|
100
|
+
warn("Details on how to use and modify Selenium logger:\n", id: [:logger_info]) do
|
|
101
|
+
"https://selenium.dev/documentation/webdriver/troubleshooting/logging#ruby\n"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
97
105
|
id = Array(id)
|
|
98
106
|
return if (@ignored & id).any?
|
|
99
107
|
|
|
@@ -104,33 +104,6 @@ module Selenium
|
|
|
104
104
|
@timeouts ||= Timeouts.new(@bridge)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
def logs
|
|
108
|
-
WebDriver.logger.deprecate('Manager#logs', 'Chrome::Driver#logs')
|
|
109
|
-
@logs ||= Logs.new(@bridge)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
#
|
|
113
|
-
# @param type [Symbol] Supports two values: :tab and :window.
|
|
114
|
-
# @return [String] The value of the window handle
|
|
115
|
-
#
|
|
116
|
-
def new_window(type = :tab)
|
|
117
|
-
WebDriver.logger.deprecate('Manager#new_window', 'TargetLocator#new_window', id: :new_window) do
|
|
118
|
-
'e.g., `driver.switch_to.new_window(:tab)`'
|
|
119
|
-
end
|
|
120
|
-
case type
|
|
121
|
-
when :tab, :window
|
|
122
|
-
result = @bridge.new_window(type)
|
|
123
|
-
unless result.key?('handle')
|
|
124
|
-
raise UnknownError, "the driver did not return a handle. " \
|
|
125
|
-
"The returned result: #{result.inspect}"
|
|
126
|
-
end
|
|
127
|
-
result['handle']
|
|
128
|
-
else
|
|
129
|
-
raise ArgumentError, "invalid argument for type. Got: '#{type.inspect}'. " \
|
|
130
|
-
"Try :tab or :window"
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
107
|
def window
|
|
135
108
|
@window ||= Window.new(@bridge)
|
|
136
109
|
end
|
|
@@ -38,12 +38,12 @@ module Selenium
|
|
|
38
38
|
def ie(**opts)
|
|
39
39
|
IE::Options.new(**opts)
|
|
40
40
|
end
|
|
41
|
-
|
|
41
|
+
alias internet_explorer ie
|
|
42
42
|
|
|
43
43
|
def edge(**opts)
|
|
44
44
|
Edge::Options.new(**opts)
|
|
45
45
|
end
|
|
46
|
-
|
|
46
|
+
alias microsoftedge edge
|
|
47
47
|
|
|
48
48
|
def safari(**opts)
|
|
49
49
|
Safari::Options.new(**opts)
|
|
@@ -66,17 +66,10 @@ module Selenium
|
|
|
66
66
|
|
|
67
67
|
attr_accessor :options
|
|
68
68
|
|
|
69
|
-
def initialize(
|
|
69
|
+
def initialize(**opts)
|
|
70
70
|
self.class.set_capabilities
|
|
71
71
|
|
|
72
|
-
@options =
|
|
73
|
-
WebDriver.logger.deprecate(":options as keyword for initializing #{self.class}",
|
|
74
|
-
"custom values directly in #new constructor",
|
|
75
|
-
id: :options_options)
|
|
76
|
-
opts.merge(options)
|
|
77
|
-
else
|
|
78
|
-
opts
|
|
79
|
-
end
|
|
72
|
+
@options = opts
|
|
80
73
|
@options[:browser_name] = self.class::BROWSER
|
|
81
74
|
end
|
|
82
75
|
|
|
@@ -92,7 +85,13 @@ module Selenium
|
|
|
92
85
|
#
|
|
93
86
|
|
|
94
87
|
def add_option(name, value = nil)
|
|
95
|
-
|
|
88
|
+
name, value = name.first if value.nil? && name.is_a?(Hash)
|
|
89
|
+
|
|
90
|
+
unless name.to_s.include?(':')
|
|
91
|
+
WebDriver.logger.deprecate('Options#add_option for w3c or browser specific capabilities',
|
|
92
|
+
'applicable attribute accessors or pass into constructor',
|
|
93
|
+
id: :add_option)
|
|
94
|
+
end
|
|
96
95
|
@options[name] = value
|
|
97
96
|
end
|
|
98
97
|
|
|
@@ -102,7 +101,7 @@ module Selenium
|
|
|
102
101
|
as_json == other.as_json
|
|
103
102
|
end
|
|
104
103
|
|
|
105
|
-
|
|
104
|
+
alias eql? ==
|
|
106
105
|
|
|
107
106
|
#
|
|
108
107
|
# @api private
|
|
@@ -113,11 +112,27 @@ module Selenium
|
|
|
113
112
|
|
|
114
113
|
w3c_options = process_w3c_options(options)
|
|
115
114
|
|
|
116
|
-
self.class::CAPABILITIES.
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
browser_options = self.class::CAPABILITIES.each_with_object({}) do |(capability_alias, capability_name), hash|
|
|
116
|
+
from_name = options.delete(capability_name)
|
|
117
|
+
from_alias = options.delete(capability_alias)
|
|
118
|
+
capability_value = if !from_name.nil? && capability_alias != capability_name
|
|
119
|
+
WebDriver.logger.deprecate("#{capability_name} as option",
|
|
120
|
+
capability_alias.to_s, id: :option_symbols)
|
|
121
|
+
from_name
|
|
122
|
+
elsif !from_alias.nil?
|
|
123
|
+
from_alias
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
hash[capability_name] = capability_value unless capability_value.nil?
|
|
119
127
|
end
|
|
120
|
-
|
|
128
|
+
|
|
129
|
+
unless options.empty?
|
|
130
|
+
msg = 'These options are not w3c compliant and will result in failures in a future release'
|
|
131
|
+
WebDriver.logger.warn("#{msg}: #{options}")
|
|
132
|
+
browser_options.merge!(options)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
browser_options = {self.class::KEY => browser_options} if defined?(self.class::KEY)
|
|
121
136
|
|
|
122
137
|
process_browser_options(browser_options)
|
|
123
138
|
generate_as_json(w3c_options.merge(browser_options))
|
|
@@ -78,6 +78,10 @@ module Selenium
|
|
|
78
78
|
engine == :jruby
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
def truffleruby?
|
|
82
|
+
engine == :truffleruby
|
|
83
|
+
end
|
|
84
|
+
|
|
81
85
|
def ruby_version
|
|
82
86
|
RUBY_VERSION
|
|
83
87
|
end
|
|
@@ -104,8 +108,7 @@ module Selenium
|
|
|
104
108
|
end
|
|
105
109
|
|
|
106
110
|
def cygwin?
|
|
107
|
-
RUBY_PLATFORM
|
|
108
|
-
!Regexp.last_match.nil?
|
|
111
|
+
RUBY_PLATFORM.include?('cygwin')
|
|
109
112
|
end
|
|
110
113
|
|
|
111
114
|
def null_device
|
|
@@ -177,9 +180,9 @@ module Selenium
|
|
|
177
180
|
|
|
178
181
|
def find_in_program_files(*binary_names)
|
|
179
182
|
paths = [
|
|
180
|
-
ENV
|
|
181
|
-
ENV
|
|
182
|
-
ENV
|
|
183
|
+
ENV.fetch('PROGRAMFILES', '\\Program Files'),
|
|
184
|
+
ENV.fetch('ProgramFiles(x86)', '\\Program Files (x86)'),
|
|
185
|
+
ENV.fetch('ProgramW6432', '\\Program Files')
|
|
183
186
|
]
|
|
184
187
|
|
|
185
188
|
paths.each do |root|
|
|
@@ -61,9 +61,6 @@ module Selenium
|
|
|
61
61
|
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
|
62
62
|
|
|
63
63
|
bridge.find_element_by by, what, ref
|
|
64
|
-
rescue Selenium::WebDriver::Error::TimeoutError
|
|
65
|
-
# Implicit Wait times out in Edge
|
|
66
|
-
raise Selenium::WebDriver::Error::NoSuchElementError
|
|
67
64
|
end
|
|
68
65
|
|
|
69
66
|
#
|
|
@@ -79,9 +76,6 @@ module Selenium
|
|
|
79
76
|
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
|
80
77
|
|
|
81
78
|
bridge.find_elements_by by, what, ref
|
|
82
|
-
rescue Selenium::WebDriver::Error::TimeoutError
|
|
83
|
-
# Implicit Wait times out in Edge
|
|
84
|
-
[]
|
|
85
79
|
end
|
|
86
80
|
|
|
87
81
|
private
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
|
5
|
+
# distributed with this work for additional information
|
|
6
|
+
# regarding copyright ownership. The SFC licenses this file
|
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
|
8
|
+
# "License"); you may not use this file except in compliance
|
|
9
|
+
# with the License. You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
|
14
|
+
# software distributed under the License is distributed on an
|
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
# KIND, either express or implied. See the License for the
|
|
17
|
+
# specific language governing permissions and limitations
|
|
18
|
+
# under the License.
|
|
19
|
+
|
|
20
|
+
require 'open3'
|
|
21
|
+
|
|
22
|
+
module Selenium
|
|
23
|
+
module WebDriver
|
|
24
|
+
#
|
|
25
|
+
# Wrapper for getting information from the Selenium Manager binaries.
|
|
26
|
+
# This implementation is still in beta, and may change.
|
|
27
|
+
# @api private
|
|
28
|
+
#
|
|
29
|
+
class SeleniumManager
|
|
30
|
+
BIN_PATH = '../../../../../bin'
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
# @param [String] driver_name which driver to use.
|
|
34
|
+
# @return [String] the path to the correct driver.
|
|
35
|
+
def driver_path(driver_name)
|
|
36
|
+
unless %w[chromedriver geckodriver msedgedriver IEDriverServer].include?(driver_name)
|
|
37
|
+
msg = "Unable to locate driver with name: #{driver_name}"
|
|
38
|
+
raise Error::WebDriverError, msg
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
location = run("#{binary} --driver #{driver_name}")
|
|
42
|
+
WebDriver.logger.debug("Driver found at #{location}")
|
|
43
|
+
Platform.assert_executable location
|
|
44
|
+
|
|
45
|
+
location
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# @return [String] the path to the correct selenium manager
|
|
51
|
+
def binary
|
|
52
|
+
@binary ||= begin
|
|
53
|
+
path = File.expand_path(BIN_PATH, __FILE__)
|
|
54
|
+
path << if Platform.windows?
|
|
55
|
+
'/windows/selenium-manager.exe'
|
|
56
|
+
elsif Platform.mac?
|
|
57
|
+
'/macos/selenium-manager'
|
|
58
|
+
elsif Platform.linux?
|
|
59
|
+
'/linux/selenium-manager'
|
|
60
|
+
end
|
|
61
|
+
location = File.expand_path(path, __FILE__)
|
|
62
|
+
unless location.is_a?(String) && File.exist?(location) && File.executable?(location)
|
|
63
|
+
raise Error::WebDriverError, 'Unable to obtain Selenium Manager'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
WebDriver.logger.debug("Selenium Manager found at #{location}")
|
|
67
|
+
location
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def run(command)
|
|
72
|
+
WebDriver.logger.debug("Executing Process #{command}")
|
|
73
|
+
|
|
74
|
+
begin
|
|
75
|
+
stdout, stderr, status = Open3.capture3(command)
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
raise Error::WebDriverError, "Unsuccessful command executed: #{command}", e.message
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if status.exitstatus.positive?
|
|
81
|
+
raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{stdout}#{stderr}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
stdout.gsub("INFO\t", '').strip
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end # SeleniumManager
|
|
88
|
+
end # WebDriver
|
|
89
|
+
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, :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.
|
|
@@ -74,15 +75,13 @@ module Selenium
|
|
|
74
75
|
@host = Platform.localhost
|
|
75
76
|
@port = Integer(port)
|
|
76
77
|
|
|
77
|
-
@
|
|
78
|
+
@args = args.is_a?(Hash) ? extract_service_args(args) : args
|
|
78
79
|
|
|
79
80
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
|
80
81
|
end
|
|
81
82
|
|
|
82
83
|
def launch
|
|
83
|
-
|
|
84
|
-
sm.start
|
|
85
|
-
sm
|
|
84
|
+
ServiceManager.new(self).tap(&:start)
|
|
86
85
|
end
|
|
87
86
|
|
|
88
87
|
def shutdown_supported
|
|
@@ -92,6 +91,9 @@ module Selenium
|
|
|
92
91
|
protected
|
|
93
92
|
|
|
94
93
|
def extract_service_args(driver_opts)
|
|
94
|
+
WebDriver.logger.deprecate('initializing Service class with :args using Hash',
|
|
95
|
+
':args parameter with an Array of String values',
|
|
96
|
+
id: :driver_opts)
|
|
95
97
|
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
|
96
98
|
end
|
|
97
99
|
|
|
@@ -101,6 +103,12 @@ module Selenium
|
|
|
101
103
|
path = path.call if path.is_a?(Proc)
|
|
102
104
|
path ||= Platform.find_binary(self.class::EXECUTABLE)
|
|
103
105
|
|
|
106
|
+
begin
|
|
107
|
+
path ||= SeleniumManager.driver_path(self.class::EXECUTABLE)
|
|
108
|
+
rescue Error::WebDriverError => e
|
|
109
|
+
WebDriver.logger.debug("Unable obtain driver using Selenium Manager\n #{e.message}")
|
|
110
|
+
end
|
|
111
|
+
|
|
104
112
|
raise Error::WebDriverError, self.class::MISSING_TEXT unless path
|
|
105
113
|
|
|
106
114
|
Platform.assert_executable path
|
|
@@ -40,7 +40,7 @@ module Selenium
|
|
|
40
40
|
@executable_path = config.executable_path
|
|
41
41
|
@host = Platform.localhost
|
|
42
42
|
@port = config.port
|
|
43
|
-
@extra_args = config.
|
|
43
|
+
@extra_args = config.args
|
|
44
44
|
@shutdown_supported = config.shutdown_supported
|
|
45
45
|
|
|
46
46
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
|
@@ -49,7 +49,7 @@ module Selenium
|
|
|
49
49
|
def start
|
|
50
50
|
raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
|
|
51
51
|
|
|
52
|
-
Platform.exit_hook
|
|
52
|
+
Platform.exit_hook { stop } # make sure we don't leave the server running
|
|
53
53
|
|
|
54
54
|
socket_lock.locked do
|
|
55
55
|
find_free_port
|
|
@@ -60,6 +60,7 @@ module Selenium
|
|
|
60
60
|
|
|
61
61
|
def stop
|
|
62
62
|
return unless @shutdown_supported
|
|
63
|
+
return if process_exited?
|
|
63
64
|
|
|
64
65
|
stop_server
|
|
65
66
|
@process.poll_for_exit STOP_TIMEOUT
|
|
@@ -78,12 +79,7 @@ module Selenium
|
|
|
78
79
|
def build_process(*command)
|
|
79
80
|
WebDriver.logger.debug("Executing Process #{command}")
|
|
80
81
|
@process = ChildProcess.build(*command)
|
|
81
|
-
if WebDriver.logger.debug?
|
|
82
|
-
@process.io.stdout = @process.io.stderr = WebDriver.logger.io
|
|
83
|
-
elsif Platform.jruby?
|
|
84
|
-
# Apparently we need to read the output of drivers on JRuby.
|
|
85
|
-
@process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
|
|
86
|
-
end
|
|
82
|
+
@process.io = WebDriver.logger.io if WebDriver.logger.debug?
|
|
87
83
|
|
|
88
84
|
@process
|
|
89
85
|
end
|
|
@@ -103,8 +99,6 @@ module Selenium
|
|
|
103
99
|
|
|
104
100
|
def start_process
|
|
105
101
|
@process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
|
|
106
|
-
# NOTE: this is a bug only in Windows 7
|
|
107
|
-
@process.leader = true unless Platform.windows?
|
|
108
102
|
@process.start
|
|
109
103
|
end
|
|
110
104
|
|
|
@@ -112,12 +106,9 @@ module Selenium
|
|
|
112
106
|
return if process_exited?
|
|
113
107
|
|
|
114
108
|
@process.stop STOP_TIMEOUT
|
|
115
|
-
@process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
|
|
116
109
|
end
|
|
117
110
|
|
|
118
111
|
def stop_server
|
|
119
|
-
return if process_exited?
|
|
120
|
-
|
|
121
112
|
connect_to_server do |http|
|
|
122
113
|
headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
|
|
123
114
|
http.get('/shutdown', headers)
|
|
@@ -42,10 +42,10 @@ module Selenium
|
|
|
42
42
|
def ==(other)
|
|
43
43
|
other.is_a?(self.class) && ref == other.ref
|
|
44
44
|
end
|
|
45
|
-
|
|
45
|
+
alias eql? ==
|
|
46
46
|
|
|
47
47
|
def hash
|
|
48
|
-
@id
|
|
48
|
+
[@id, @bridge].hash
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
#
|
|
@@ -81,7 +81,6 @@ module Selenium
|
|
|
81
81
|
private
|
|
82
82
|
|
|
83
83
|
attr_reader :bridge
|
|
84
|
-
|
|
85
84
|
end # ShadowRoot
|
|
86
85
|
end # WebDriver
|
|
87
86
|
end # Selenium
|
|
@@ -26,6 +26,7 @@ module Selenium
|
|
|
26
26
|
class SocketLock
|
|
27
27
|
def initialize(port, timeout)
|
|
28
28
|
@port = port
|
|
29
|
+
@server = nil
|
|
29
30
|
@timeout = timeout
|
|
30
31
|
end
|
|
31
32
|
|
|
@@ -66,8 +67,7 @@ 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
73
|
WebDriver.logger.debug("#{self}: #{e.message}")
|
|
@@ -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.
|