selenium-webdriver 4.12.0 → 4.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +135 -1
  3. data/Gemfile +1 -0
  4. data/LICENSE +1 -1
  5. data/NOTICE +1 -1
  6. data/README.md +2 -2
  7. data/bin/linux/selenium-manager +0 -0
  8. data/bin/macos/selenium-manager +0 -0
  9. data/bin/windows/selenium-manager.exe +0 -0
  10. data/lib/selenium/server.rb +2 -1
  11. data/lib/selenium/webdriver/atoms/findElements.js +28 -27
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +6 -100
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +24 -96
  14. data/lib/selenium/webdriver/atoms.rb +6 -3
  15. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +1 -1
  16. data/lib/selenium/webdriver/bidi/log_handler.rb +63 -0
  17. data/lib/selenium/webdriver/bidi/log_inspector.rb +5 -1
  18. data/lib/selenium/webdriver/bidi/session.rb +7 -7
  19. data/lib/selenium/webdriver/bidi/struct.rb +44 -0
  20. data/lib/selenium/webdriver/bidi.rb +10 -0
  21. data/lib/selenium/webdriver/chrome/features.rb +5 -1
  22. data/lib/selenium/webdriver/chrome/service.rb +7 -0
  23. data/lib/selenium/webdriver/chromium/driver.rb +1 -1
  24. data/lib/selenium/webdriver/chromium/features.rb +0 -4
  25. data/lib/selenium/webdriver/common/action_builder.rb +0 -4
  26. data/lib/selenium/webdriver/common/child_process.rb +8 -2
  27. data/lib/selenium/webdriver/common/driver.rb +23 -17
  28. data/lib/selenium/webdriver/common/driver_extensions/has_bidi.rb +1 -1
  29. data/lib/selenium/webdriver/common/driver_extensions/has_fedcm_dialog.rb +55 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +65 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
  32. data/lib/selenium/webdriver/common/driver_finder.rb +66 -14
  33. data/lib/selenium/webdriver/common/error.rb +22 -22
  34. data/lib/selenium/webdriver/common/fedcm/account.rb +50 -0
  35. data/lib/selenium/webdriver/common/fedcm/dialog.rb +74 -0
  36. data/lib/selenium/webdriver/common/fedcm.rb +27 -0
  37. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +0 -1
  38. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +1 -1
  39. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +2 -1
  40. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +1 -1
  41. data/lib/selenium/webdriver/common/local_driver.rb +8 -1
  42. data/lib/selenium/webdriver/common/logger.rb +7 -7
  43. data/lib/selenium/webdriver/common/manager.rb +1 -1
  44. data/lib/selenium/webdriver/common/options.rb +6 -2
  45. data/lib/selenium/webdriver/common/platform.rb +7 -1
  46. data/lib/selenium/webdriver/common/proxy.rb +2 -2
  47. data/lib/selenium/webdriver/common/script.rb +45 -0
  48. data/lib/selenium/webdriver/common/search_context.rb +10 -2
  49. data/lib/selenium/webdriver/common/selenium_manager.rb +34 -59
  50. data/lib/selenium/webdriver/common/service.rb +4 -0
  51. data/lib/selenium/webdriver/common/service_manager.rb +1 -1
  52. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  53. data/lib/selenium/webdriver/common/takes_screenshot.rb +4 -2
  54. data/lib/selenium/webdriver/common/websocket_connection.rb +12 -0
  55. data/lib/selenium/webdriver/common.rb +5 -2
  56. data/lib/selenium/webdriver/devtools/network_interceptor.rb +1 -1
  57. data/lib/selenium/webdriver/edge/features.rb +5 -1
  58. data/lib/selenium/webdriver/edge/service.rb +7 -0
  59. data/lib/selenium/webdriver/firefox/features.rb +5 -1
  60. data/lib/selenium/webdriver/firefox/options.rb +3 -0
  61. data/lib/selenium/webdriver/firefox/profile.rb +14 -6
  62. data/lib/selenium/webdriver/firefox/profiles_ini.rb +1 -1
  63. data/lib/selenium/webdriver/{common/driver_extensions/has_location.rb → ie/features.rb} +8 -10
  64. data/lib/selenium/webdriver/ie/options.rb +3 -2
  65. data/lib/selenium/webdriver/ie.rb +4 -3
  66. data/lib/selenium/webdriver/{common/driver_extensions/has_network_connection.rb → remote/bidi_bridge.rb} +18 -11
  67. data/lib/selenium/webdriver/remote/bridge/commands.rb +13 -7
  68. data/lib/selenium/webdriver/remote/bridge/locator_converter.rb +76 -0
  69. data/lib/selenium/webdriver/remote/bridge.rb +87 -69
  70. data/lib/selenium/webdriver/remote/capabilities.rb +2 -2
  71. data/lib/selenium/webdriver/remote/driver.rb +4 -0
  72. data/lib/selenium/webdriver/remote/features.rb +75 -0
  73. data/lib/selenium/webdriver/remote/http/common.rb +21 -3
  74. data/lib/selenium/webdriver/remote/response.rb +8 -33
  75. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  76. data/lib/selenium/webdriver/remote.rb +2 -0
  77. data/lib/selenium/webdriver/safari/features.rb +5 -1
  78. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  79. data/lib/selenium/webdriver/support/guards/guard.rb +14 -12
  80. data/lib/selenium/webdriver/support/guards.rb +1 -1
  81. data/lib/selenium/webdriver/version.rb +1 -1
  82. data/lib/selenium/webdriver.rb +1 -1
  83. data/selenium-webdriver.gemspec +9 -7
  84. 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
- # If no top-level browsing contexts are open after calling close,
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&.browser
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::Bridge.new(http_client: http_client, url: url).tap do |bridge|
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
@@ -28,7 +28,7 @@ module Selenium
28
28
  #
29
29
 
30
30
  def bidi
31
- @bidi ||= Selenium::WebDriver::BiDi.new(url: capabilities[:web_socket_url])
31
+ @bridge.bidi
32
32
  end
33
33
  end # HasBiDi
34
34
  end # DriverExtensions
@@ -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
@@ -64,7 +64,7 @@ module Selenium
64
64
  return if enabled
65
65
 
66
66
  devtools.runtime.enable
67
- __send__("log_#{kind}_events")
67
+ __send__(:"log_#{kind}_events")
68
68
  end
69
69
 
70
70
  private
@@ -20,25 +20,77 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  class DriverFinder
23
- def self.path(options, klass)
24
- path = klass.driver_path
25
- path = path.call if path.is_a?(Proc)
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
- path ||= begin
28
- SeleniumManager.driver_path(options) unless options.is_a?(Remote::Capabilities)
70
+ formatted
71
+ end
29
72
  rescue StandardError => e
30
- raise Error::NoSuchDriverError, "Unable to obtain #{klass::EXECUTABLE} using Selenium Manager; #{e.message}"
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
- begin
34
- Platform.assert_executable(path)
35
- rescue TypeError
36
- raise Error::NoSuchDriverError, "Unable to locate or obtain #{klass::EXECUTABLE}"
37
- rescue Error::WebDriverError => e
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
- path
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
- class WebDriverError < StandardError; end
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
 
@@ -28,7 +28,7 @@ module Selenium
28
28
 
29
29
  class PointerCancel < Interaction
30
30
  def initialize(source)
31
- super(source)
31
+ super
32
32
  @type = :pointerCancel
33
33
  end
34
34
 
@@ -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)
@@ -28,7 +28,7 @@ module Selenium
28
28
 
29
29
  class WheelInput < InputDevice
30
30
  def initialize(name = nil)
31
- super(name)
31
+ super
32
32
  @type = Interactions::WHEEL
33
33
  end
34
34
 
@@ -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 ||= WebDriver::DriverFinder.path(options, service.class)
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