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
@@ -43,7 +43,7 @@ module Selenium
|
|
43
43
|
|
44
44
|
def for(browser, opts = {})
|
45
45
|
case browser
|
46
|
-
when :chrome
|
46
|
+
when :chrome, :chrome_headless_shell
|
47
47
|
Chrome::Driver.new(**opts)
|
48
48
|
when :internet_explorer, :ie
|
49
49
|
IE::Driver.new(**opts)
|
@@ -70,10 +70,9 @@ module Selenium
|
|
70
70
|
|
71
71
|
def initialize(bridge: nil, listener: nil, **opts)
|
72
72
|
@devtools = nil
|
73
|
-
@bidi = nil
|
74
73
|
bridge ||= create_bridge(**opts)
|
75
|
-
add_extensions(bridge.browser)
|
76
74
|
@bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
|
75
|
+
add_extensions(@bridge.browser)
|
77
76
|
end
|
78
77
|
|
79
78
|
def inspect
|
@@ -100,6 +99,22 @@ module Selenium
|
|
100
99
|
@navigate ||= WebDriver::Navigation.new(bridge)
|
101
100
|
end
|
102
101
|
|
102
|
+
#
|
103
|
+
# @return [Script]
|
104
|
+
# @see Script
|
105
|
+
#
|
106
|
+
|
107
|
+
def script(*args)
|
108
|
+
if args.any?
|
109
|
+
WebDriver.logger.deprecate('`Driver#script` as an alias for `#execute_script`',
|
110
|
+
'`Driver#execute_script`',
|
111
|
+
id: :driver_script)
|
112
|
+
execute_script(*args)
|
113
|
+
else
|
114
|
+
@script ||= WebDriver::Script.new(bridge)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
103
118
|
#
|
104
119
|
# @return [TargetLocator]
|
105
120
|
# @see TargetLocator
|
@@ -174,7 +189,6 @@ module Selenium
|
|
174
189
|
ensure
|
175
190
|
@service_manager&.stop
|
176
191
|
@devtools&.close
|
177
|
-
@bidi&.close
|
178
192
|
end
|
179
193
|
|
180
194
|
#
|
@@ -182,10 +196,7 @@ module Selenium
|
|
182
196
|
#
|
183
197
|
|
184
198
|
def close
|
185
|
-
|
186
|
-
# it indicates that the WebDriver session is closed.
|
187
|
-
# If the WebDriver session is closed, the BiDi session also needs to be closed.
|
188
|
-
bridge.close.tap { |handles| @bidi&.close if handles&.empty? }
|
199
|
+
bridge&.close
|
189
200
|
end
|
190
201
|
|
191
202
|
#
|
@@ -267,12 +278,6 @@ module Selenium
|
|
267
278
|
|
268
279
|
alias all find_elements
|
269
280
|
|
270
|
-
#
|
271
|
-
# driver.script('function() { ... };')
|
272
|
-
#
|
273
|
-
|
274
|
-
alias script execute_script
|
275
|
-
|
276
281
|
# Get the first element matching the given selector. If given a
|
277
282
|
# String or Symbol, it will be used as the id of the element.
|
278
283
|
#
|
@@ -292,7 +297,7 @@ module Selenium
|
|
292
297
|
end
|
293
298
|
|
294
299
|
def browser
|
295
|
-
bridge
|
300
|
+
bridge.browser
|
296
301
|
end
|
297
302
|
|
298
303
|
def capabilities
|
@@ -313,7 +318,8 @@ module Selenium
|
|
313
318
|
attr_reader :bridge
|
314
319
|
|
315
320
|
def create_bridge(caps:, url:, http_client: nil)
|
316
|
-
Remote::
|
321
|
+
klass = caps['webSocketUrl'] ? Remote::BiDiBridge : Remote::Bridge
|
322
|
+
klass.new(http_client: http_client, url: url).tap do |bridge|
|
317
323
|
bridge.create_session(caps)
|
318
324
|
end
|
319
325
|
end
|
@@ -329,7 +335,7 @@ module Selenium
|
|
329
335
|
|
330
336
|
def add_extensions(browser)
|
331
337
|
extensions = case browser
|
332
|
-
when :chrome, :msedge
|
338
|
+
when :chrome, :chrome_headless_shell, :msedge, :microsoftedge
|
333
339
|
Chromium::Driver::EXTENSIONS
|
334
340
|
when :firefox
|
335
341
|
Firefox::Driver::EXTENSIONS
|
@@ -0,0 +1,55 @@
|
|
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 DriverExtensions
|
23
|
+
module HasFedCmDialog
|
24
|
+
# Disables the promise rejection delay for FedCm.
|
25
|
+
#
|
26
|
+
# FedCm by default delays promise resolution in failure cases for privacy reasons.
|
27
|
+
# This method allows turning it off to let tests run faster where this is not relevant.
|
28
|
+
def enable_fedcm_delay=(enable)
|
29
|
+
@bridge.fedcm_delay(enable)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Resets the FedCm dialog cooldown.
|
33
|
+
#
|
34
|
+
# If a user agent triggers a cooldown when the account chooser is dismissed,
|
35
|
+
# this method resets that cooldown so that the dialog can be triggered again immediately.
|
36
|
+
def reset_fedcm_cooldown
|
37
|
+
@bridge.reset_fedcm_cooldown
|
38
|
+
end
|
39
|
+
|
40
|
+
def fedcm_dialog
|
41
|
+
@fedcm_dialog ||= FedCM::Dialog.new(@bridge)
|
42
|
+
end
|
43
|
+
|
44
|
+
def wait_for_fedcm_dialog(timeout: 5, interval: 0.2, message: nil, ignore: nil)
|
45
|
+
wait = Wait.new(timeout: timeout, interval: interval, message: message, ignore: ignore)
|
46
|
+
wait.until do
|
47
|
+
fedcm_dialog if fedcm_dialog.type
|
48
|
+
rescue Error::NoSuchAlertError
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end # HasFedCmDialog
|
53
|
+
end # DriverExtensions
|
54
|
+
end # WebDriver
|
55
|
+
end # Selenium
|
@@ -0,0 +1,65 @@
|
|
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 DriverExtensions
|
23
|
+
module HasFileDownloads
|
24
|
+
def downloadable_files
|
25
|
+
verify_enabled
|
26
|
+
|
27
|
+
@bridge.downloadable_files['names']
|
28
|
+
end
|
29
|
+
|
30
|
+
def download_file(file_name, target_directory)
|
31
|
+
verify_enabled
|
32
|
+
|
33
|
+
response = @bridge.download_file(file_name)
|
34
|
+
contents = response['contents']
|
35
|
+
|
36
|
+
File.open("#{file_name}.zip", 'wb') { |f| f << Base64.decode64(contents) }
|
37
|
+
target_directory += '/' unless target_directory.end_with?('/')
|
38
|
+
FileUtils.mkdir_p(target_directory)
|
39
|
+
|
40
|
+
begin
|
41
|
+
Zip::File.open("#{file_name}.zip") do |zip|
|
42
|
+
zip.each { |entry| zip.extract(entry, "#{target_directory}#{file_name}") }
|
43
|
+
end
|
44
|
+
ensure
|
45
|
+
FileUtils.rm_f("#{file_name}.zip")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete_downloadable_files
|
50
|
+
verify_enabled
|
51
|
+
|
52
|
+
@bridge.delete_downloadable_files
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def verify_enabled
|
58
|
+
return if capabilities['se:downloadsEnabled']
|
59
|
+
|
60
|
+
raise Error::WebDriverError, 'You must enable downloads in order to work with downloadable files.'
|
61
|
+
end
|
62
|
+
end # HasFileDownloads
|
63
|
+
end # DriverExtensions
|
64
|
+
end # WebDriver
|
65
|
+
end # Selenium
|
@@ -20,25 +20,77 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
class DriverFinder
|
23
|
-
def self.path(options,
|
24
|
-
path
|
25
|
-
|
23
|
+
def self.path(options, service_class)
|
24
|
+
WebDriver.logger.deprecate('DriverFinder.path(options, service_class)',
|
25
|
+
'DriverFinder.new(options, service).driver_path')
|
26
|
+
new(options, service_class.new).driver_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(options, service)
|
30
|
+
@options = options
|
31
|
+
@service = service
|
32
|
+
end
|
33
|
+
|
34
|
+
def browser_path
|
35
|
+
paths[:browser_path]
|
36
|
+
end
|
37
|
+
|
38
|
+
def driver_path
|
39
|
+
paths[:driver_path]
|
40
|
+
end
|
41
|
+
|
42
|
+
def browser_path?
|
43
|
+
!browser_path.nil? && !browser_path.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def paths
|
49
|
+
@paths ||= begin
|
50
|
+
path = @service.class.driver_path
|
51
|
+
path = path.call if path.is_a?(Proc)
|
52
|
+
exe = @service.class::EXECUTABLE
|
53
|
+
if path
|
54
|
+
WebDriver.logger.debug("Skipping Selenium Manager; path to #{exe} specified in service class: #{path}")
|
55
|
+
Platform.assert_executable(path)
|
56
|
+
{driver_path: path}
|
57
|
+
else
|
58
|
+
output = SeleniumManager.binary_paths(*to_args)
|
59
|
+
formatted = {driver_path: Platform.cygwin_path(output['driver_path'], only_cygwin: true),
|
60
|
+
browser_path: Platform.cygwin_path(output['browser_path'], only_cygwin: true)}
|
61
|
+
Platform.assert_executable(formatted[:driver_path])
|
62
|
+
|
63
|
+
browser_path = formatted[:browser_path]
|
64
|
+
Platform.assert_executable(browser_path)
|
65
|
+
if @options.respond_to?(:binary) && @options.binary.nil?
|
66
|
+
@options.binary = browser_path
|
67
|
+
@options.browser_version = nil
|
68
|
+
end
|
26
69
|
|
27
|
-
|
28
|
-
|
70
|
+
formatted
|
71
|
+
end
|
29
72
|
rescue StandardError => e
|
30
|
-
|
73
|
+
WebDriver.logger.error("Exception occurred: #{e.message}")
|
74
|
+
WebDriver.logger.error("Backtrace:\n\t#{e.backtrace&.join("\n\t")}")
|
75
|
+
raise Error::NoSuchDriverError, "Unable to obtain #{exe}"
|
31
76
|
end
|
77
|
+
end
|
32
78
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
raise Error::NoSuchDriverError, "#{klass::EXECUTABLE} located, but: #{e.message}"
|
79
|
+
def to_args
|
80
|
+
args = ['--browser', @options.browser_name]
|
81
|
+
if @options.browser_version
|
82
|
+
args << '--browser-version'
|
83
|
+
args << @options.browser_version
|
39
84
|
end
|
40
|
-
|
41
|
-
|
85
|
+
if @options.respond_to?(:binary) && !@options.binary.nil?
|
86
|
+
args << '--browser-path'
|
87
|
+
args << @options.binary.gsub('\\', '\\\\\\')
|
88
|
+
end
|
89
|
+
if @options.proxy
|
90
|
+
args << '--proxy'
|
91
|
+
args << (@options.proxy.ssl || @options.proxy.http)
|
92
|
+
end
|
93
|
+
args
|
42
94
|
end
|
43
95
|
end
|
44
96
|
end
|
@@ -29,7 +29,7 @@ module Selenium
|
|
29
29
|
return if error.nil?
|
30
30
|
|
31
31
|
klass_name = error.split.map(&:capitalize).join.sub(/Error$/, '')
|
32
|
-
const_get("#{klass_name}Error", false)
|
32
|
+
const_get(:"#{klass_name}Error", false)
|
33
33
|
rescue NameError
|
34
34
|
WebDriverError
|
35
35
|
end
|
@@ -37,17 +37,29 @@ module Selenium
|
|
37
37
|
SUPPORT_MSG = 'For documentation on this error, please visit:'
|
38
38
|
ERROR_URL = 'https://www.selenium.dev/documentation/webdriver/troubleshooting/errors'
|
39
39
|
|
40
|
-
|
40
|
+
URLS = {
|
41
|
+
NoSuchElementError: "#{ERROR_URL}#no-such-element-exception",
|
42
|
+
StaleElementReferenceError: "#{ERROR_URL}#stale-element-reference-exception",
|
43
|
+
InvalidSelectorError: "#{ERROR_URL}#invalid-selector-exception",
|
44
|
+
NoSuchDriverError: "#{ERROR_URL}/driver_location"
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
class WebDriverError < StandardError
|
48
|
+
def initialize(msg = '')
|
49
|
+
# Remove this conditional when all the error pages have been documented
|
50
|
+
super(URLS[class_name] ? "#{msg}; #{SUPPORT_MSG} #{URLS[class_name]}" : msg)
|
51
|
+
end
|
52
|
+
|
53
|
+
def class_name
|
54
|
+
self.class.name&.split('::')&.last&.to_sym
|
55
|
+
end
|
56
|
+
end
|
41
57
|
|
42
58
|
#
|
43
59
|
# An element could not be located on the page using the given search parameters.
|
44
60
|
#
|
45
61
|
|
46
|
-
class NoSuchElementError < WebDriverError
|
47
|
-
def initialize(msg = '')
|
48
|
-
super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}#no-such-element-exception")
|
49
|
-
end
|
50
|
-
end
|
62
|
+
class NoSuchElementError < WebDriverError; end
|
51
63
|
|
52
64
|
#
|
53
65
|
# A command to switch to a frame could not be satisfied because the frame could not be found.
|
@@ -65,11 +77,7 @@ module Selenium
|
|
65
77
|
# A command failed because the referenced element is no longer attached to the DOM.
|
66
78
|
#
|
67
79
|
|
68
|
-
class StaleElementReferenceError < WebDriverError
|
69
|
-
def initialize(msg = '')
|
70
|
-
super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}#stale-element-reference-exception")
|
71
|
-
end
|
72
|
-
end
|
80
|
+
class StaleElementReferenceError < WebDriverError; end
|
73
81
|
|
74
82
|
#
|
75
83
|
# A command failed because the referenced shadow root is no longer attached to the DOM.
|
@@ -143,11 +151,7 @@ module Selenium
|
|
143
151
|
# Argument was an invalid selector.
|
144
152
|
#
|
145
153
|
|
146
|
-
class InvalidSelectorError < WebDriverError
|
147
|
-
def initialize(msg = '')
|
148
|
-
super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}#invalid-selector-exception")
|
149
|
-
end
|
150
|
-
end
|
154
|
+
class InvalidSelectorError < WebDriverError; end
|
151
155
|
|
152
156
|
#
|
153
157
|
# A new session could not be created.
|
@@ -232,11 +236,7 @@ module Selenium
|
|
232
236
|
# Indicates that driver was not specified and could not be located.
|
233
237
|
#
|
234
238
|
|
235
|
-
class NoSuchDriverError < WebDriverError
|
236
|
-
def initialize(msg = '')
|
237
|
-
super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}/driver_location")
|
238
|
-
end
|
239
|
-
end
|
239
|
+
class NoSuchDriverError < WebDriverError; end
|
240
240
|
end # Error
|
241
241
|
end # WebDriver
|
242
242
|
end # Selenium
|
@@ -0,0 +1,50 @@
|
|
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 FedCM
|
23
|
+
# Represents an account displayed in a FedCm account list.
|
24
|
+
# See: https://fedidcg.github.io/FedCM/#dictdef-identityprovideraccount
|
25
|
+
# https://fedidcg.github.io/FedCM/#webdriver-accountlist
|
26
|
+
class Account
|
27
|
+
LOGIN_STATE_SIGNIN = 'SignIn'
|
28
|
+
LOGIN_STATE_SIGNUP = 'SignUp'
|
29
|
+
|
30
|
+
attr_reader :account_id, :email, :name, :given_name, :picture_url,
|
31
|
+
:idp_config_url, :login_state, :terms_of_service_url, :privacy_policy_url
|
32
|
+
|
33
|
+
# Initializes a new account with the provided attributes.
|
34
|
+
#
|
35
|
+
# @param [Hash]
|
36
|
+
def initialize(**args)
|
37
|
+
@account_id = args['accountId']
|
38
|
+
@email = args['email']
|
39
|
+
@name = args['name']
|
40
|
+
@given_name = args['givenName']
|
41
|
+
@picture_url = args['pictureUrl']
|
42
|
+
@idp_config_url = args['idpConfigUrl']
|
43
|
+
@login_state = args['loginState']
|
44
|
+
@terms_of_service_url = args['termsOfServiceUrl']
|
45
|
+
@privacy_policy_url = args['privacyPolicyUrl']
|
46
|
+
end
|
47
|
+
end # Account
|
48
|
+
end # FedCM
|
49
|
+
end # WebDriver
|
50
|
+
end # Selenium
|
@@ -0,0 +1,74 @@
|
|
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 FedCM
|
23
|
+
class Dialog
|
24
|
+
def initialize(bridge)
|
25
|
+
@bridge = bridge
|
26
|
+
end
|
27
|
+
|
28
|
+
DIALOG_TYPE_ACCOUNT_LIST = 'AccountChooser'
|
29
|
+
DIALOG_TYPE_AUTO_REAUTH = 'AutoReauthn'
|
30
|
+
|
31
|
+
# Closes the dialog as if the user had clicked X.
|
32
|
+
def click
|
33
|
+
@bridge.click_fedcm_dialog_button
|
34
|
+
end
|
35
|
+
|
36
|
+
# Closes the dialog as if the user had clicked X.
|
37
|
+
def cancel
|
38
|
+
@bridge.cancel_fedcm_dialog
|
39
|
+
end
|
40
|
+
|
41
|
+
# Selects an account as if the user had clicked on it.
|
42
|
+
#
|
43
|
+
# @param [Integer] index The index of the account to select from the list returned by get_accounts.
|
44
|
+
def select_account(index)
|
45
|
+
@bridge.select_fedcm_account index
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the type of the open dialog.
|
49
|
+
#
|
50
|
+
# One of DIALOG_TYPE_ACCOUNT_LIST and DIALOG_TYPE_AUTO_REAUTH.
|
51
|
+
def type
|
52
|
+
@bridge.fedcm_dialog_type
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the title of the dialog.
|
56
|
+
def title
|
57
|
+
@bridge.fedcm_title
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the subtitle of the dialog or nil if none.
|
61
|
+
def subtitle
|
62
|
+
@bridge.fedcm_subtitle
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the accounts shown in the account chooser.
|
66
|
+
#
|
67
|
+
# If this is an auto reauth dialog, returns the single account that is being signed in.
|
68
|
+
def accounts
|
69
|
+
@bridge.fedcm_account_list.map { |account| Account.new(**account) }
|
70
|
+
end
|
71
|
+
end # Dialog
|
72
|
+
end # FedCM
|
73
|
+
end # WebDriver
|
74
|
+
end # Selenium
|
@@ -0,0 +1,27 @@
|
|
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 FedCM
|
23
|
+
autoload :Account, 'fedcm/account'
|
24
|
+
autoload :Dialog, 'fedcm/dialog'
|
25
|
+
end # FedCM
|
26
|
+
end # WebDriver
|
27
|
+
end # Selenium
|
@@ -91,7 +91,6 @@ module Selenium
|
|
91
91
|
# element. A negative value means coordinates to the left of the center.
|
92
92
|
# @param [Integer] down_by Optional offset from the in-view center of the
|
93
93
|
# element. A negative value means coordinates to the top of the center.
|
94
|
-
# @param [Symbol || String] device optional name of the PointerInput device to move.
|
95
94
|
# @return [ActionBuilder] A self reference.
|
96
95
|
#
|
97
96
|
|
@@ -38,7 +38,8 @@ module Selenium
|
|
38
38
|
# el = driver.find_element(id: "some_id")
|
39
39
|
# driver.action.scroll_to(element).perform
|
40
40
|
#
|
41
|
-
# @param [Object] Which element to scroll into the viewport.
|
41
|
+
# @param [Object] element Which element to scroll into the viewport.
|
42
|
+
# @param [Object] device Which device to use to scroll
|
42
43
|
# @return [Selenium::WebDriver::WheelActions] A self reference.
|
43
44
|
def scroll_to(element, device: nil)
|
44
45
|
scroll(origin: element, device: device)
|
@@ -38,7 +38,14 @@ module Selenium
|
|
38
38
|
raise ArgumentError, ":options must be an instance of #{default_options.class}"
|
39
39
|
end
|
40
40
|
|
41
|
-
service.executable_path ||=
|
41
|
+
service.executable_path ||= begin
|
42
|
+
finder = WebDriver::DriverFinder.new(options, service)
|
43
|
+
if options.respond_to?(:binary) && finder.browser_path?
|
44
|
+
options.binary = finder.browser_path
|
45
|
+
options.browser_version = nil
|
46
|
+
end
|
47
|
+
finder.driver_path
|
48
|
+
end
|
42
49
|
options.as_json
|
43
50
|
end
|
44
51
|
end
|