selenium-webdriver 4.1.0 → 4.3.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +70 -1
  3. data/LICENSE +1 -1
  4. data/NOTICE +1 -1
  5. data/lib/selenium/server.rb +14 -9
  6. data/lib/selenium/webdriver/bidi/session.rb +38 -0
  7. data/lib/selenium/webdriver/bidi.rb +55 -0
  8. data/lib/selenium/webdriver/chrome/features.rb +5 -0
  9. data/lib/selenium/webdriver/chrome/options.rb +19 -19
  10. data/lib/selenium/webdriver/chrome.rb +0 -14
  11. data/lib/selenium/webdriver/common/action_builder.rb +108 -21
  12. data/lib/selenium/webdriver/common/driver.rb +13 -55
  13. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +12 -5
  14. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -0
  15. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -2
  16. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
  17. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -1
  18. data/lib/selenium/webdriver/common/element.rb +1 -1
  19. data/lib/selenium/webdriver/common/error.rb +1 -1
  20. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  21. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
  22. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  23. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
  24. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  25. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  26. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  27. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +56 -66
  28. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  29. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  30. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  31. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  32. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  33. data/lib/selenium/webdriver/common/interactions/scroll.rb +57 -0
  34. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  35. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  36. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  37. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
  38. data/lib/selenium/webdriver/common/keys.rb +1 -0
  39. data/lib/selenium/webdriver/common/manager.rb +0 -27
  40. data/lib/selenium/webdriver/common/options.rb +2 -9
  41. data/lib/selenium/webdriver/common/platform.rb +4 -4
  42. data/lib/selenium/webdriver/common/search_context.rb +0 -6
  43. data/lib/selenium/webdriver/common/service_manager.rb +2 -3
  44. data/lib/selenium/webdriver/common/shadow_root.rb +1 -1
  45. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  46. data/lib/selenium/webdriver/common/websocket_connection.rb +149 -0
  47. data/lib/selenium/webdriver/common.rb +14 -3
  48. data/lib/selenium/webdriver/devtools/request.rb +1 -1
  49. data/lib/selenium/webdriver/devtools/response.rb +1 -1
  50. data/lib/selenium/webdriver/devtools.rb +5 -112
  51. data/lib/selenium/webdriver/edge/features.rb +1 -0
  52. data/lib/selenium/webdriver/firefox/driver.rb +1 -0
  53. data/lib/selenium/webdriver/firefox/features.rb +2 -5
  54. data/lib/selenium/webdriver/firefox/options.rb +3 -1
  55. data/lib/selenium/webdriver/firefox/profile.rb +1 -5
  56. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  57. data/lib/selenium/webdriver/firefox.rb +1 -14
  58. data/lib/selenium/webdriver/ie.rb +0 -14
  59. data/lib/selenium/webdriver/remote/bridge.rb +21 -19
  60. data/lib/selenium/webdriver/remote/commands.rb +0 -5
  61. data/lib/selenium/webdriver/remote/driver.rb +0 -1
  62. data/lib/selenium/webdriver/remote/http/default.rb +6 -12
  63. data/lib/selenium/webdriver/remote/response.rb +2 -2
  64. data/lib/selenium/webdriver/safari.rb +0 -14
  65. data/lib/selenium/webdriver/support/cdp_client_generator.rb +4 -4
  66. data/lib/selenium/webdriver/support/color.rb +7 -7
  67. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -1
  68. data/lib/selenium/webdriver/support/guards.rb +1 -1
  69. data/lib/selenium/webdriver/version.rb +1 -1
  70. data/lib/selenium/webdriver.rb +1 -0
  71. data/selenium-webdriver.gemspec +7 -4
  72. metadata +56 -8
  73. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40e4bef1fdee7ae817c56466ec231be400d677d56a8c8f46b797c6b3eba28de9
4
- data.tar.gz: a9c1af31f12db6096f06c2a89e487e40ea2bb53b8f6e46e5f77a3046f149bb34
3
+ metadata.gz: 89c68b6ae8db07e10f1e0ead164a3d36f5294c62166d361b1ec1fa42647e3672
4
+ data.tar.gz: c1d0c0c2322acaaa95b98d5187315c975289282b3ee2085c14b86426b819de45
5
5
  SHA512:
6
- metadata.gz: b5325d0fe9f5fdb721ed4a6daa1384d7876dc7a072dd52f46c73d76b1614434c123fff2b4a9d7de01538968eddfbad57f2e1a87f4dce0e560a850dcf21988840
7
- data.tar.gz: 3b345ac66d051c32267d1c4ef9b2dd70aea36e2c4e5bb35ce30197d748effca8fed460824d1961ad5a39340358fc9be3f200708a38557e5e878b09be1b0d61c0
6
+ metadata.gz: 120b0f57601862015b62dc9ae23b510ca2433342cc500ae4fe38a70550c07e91ff20e26fd2b5a03066830b8e1f06246d1e23151070207c1c8e5e4cfc37c20889
7
+ data.tar.gz: 3664cea6889b141e7de551ed518471fc2617ae6321c56981e898249fa688564aed92c5a05dba66333bf97457ed551e7051b009340a5e9abb91249e608633b416
data/CHANGES CHANGED
@@ -1,4 +1,73 @@
1
- 4.1.0 (2021-11-18)
1
+ 4.3.0 (2022-06-23)
2
+ =========================
3
+
4
+ BiDi:
5
+ * Released selenium-devtools 0.103.0 (supports CDP v85, v101, v102, v103)
6
+
7
+ Ruby:
8
+ * Allow specifying which button is clicked in pointer action class methods
9
+ * Remove deprecated `Persistent` http class
10
+ * Remove deprecated HasRemoteStatus module
11
+ * Remove deprecated `Manager#new_window` and `Manager#logs`
12
+ * `ActionBuilder#move_to` no longer attempts to move to top left corner of element
13
+ * Remove deprecated support for sending Service parameters directly to Driver constructor
14
+ * Remove deprecated setters and getters for driver path on Browser modules
15
+ * Remove deprecated support for passing in options argument to Options class
16
+ * Allow `:options` parameter to take `Options` instance argument like other languages
17
+ * Remove deprecated support for `:desired_capabilities` & `:options` with `Hash` argument
18
+
19
+ 4.2.1 (2022-05-31)
20
+ =========================
21
+
22
+ Ruby
23
+ * Fix bug in setting default duration in Actions constructor
24
+
25
+ 4.2.0 (2022-05-27)
26
+ =========================
27
+
28
+ BiDi:
29
+ * Released selenium-devtools 0.97.0 (supports CDP v85, v95, v96, v97)
30
+ * Released selenium-devtools 0.98.0 (supports CDP v85, v96, v97, v98)
31
+ * Released selenium-devtools 0.99.0 (supports CDP v85, v97, v98, v99)
32
+ * Released selenium-devtools 0.100.0 (supports CDP v85, v98, v99, v100)
33
+ * Released selenium-devtools 0.101.0 (supports CDP v85, v99, v100, v101)
34
+ * Released selenium-devtools 0.102.0 (supports CDP v85, v100, v101, v102)
35
+ * Implement simple BiDi connection
36
+ * Fix bug in initial BiDi implementation (thanks Boris Petrov!)
37
+ * Fix bug with mutating headers in request interception (#10574)
38
+ * Fix bug with empty response headers (thanks Viren Negi!)
39
+
40
+ Firefox:
41
+ * Add support to Firefox Options for environment capability
42
+ * Use addon parameter instead of path parameter to avoid using file detector
43
+ * Restore #from_name method to Firefox profile (#10146)
44
+
45
+ Chromium:
46
+ * Add support for casting desktop
47
+
48
+ Ruby:
49
+ * Updated minimum required Ruby version to 2.7
50
+ * Fix bug by not attempting to stop service process when it's not started (#10015)
51
+ * Fix bug to not stop service process when it's not started (thanks Atsushi Tatsuma!)
52
+ * Use driver endpoint to get page source instead of JavaScript
53
+ * Add zenkaku_hankaku key support
54
+ * Fix download support of Selenium Server
55
+ * Do not convert Tag Name to CSS Selector
56
+
57
+ ActionBuilder:
58
+ * Raise error if input device not found
59
+ * Move `TypingInteraction` from `Interactions::KeyInput` to `Interactions` module
60
+ * Throw better errors for `PointerInput` methods
61
+ * Allow each action interaction class to validate its own source
62
+ * Set all Interactions classes to private
63
+ * Allow device names to use a default id if one is not specified
64
+ * Deprecate default mouse and keyboard values in constructor, favoring devices parameter
65
+ * Add support for pointer event properties
66
+ * Implement scroll wheel support
67
+ * Deprecate ordered pair parameters for pause method in favor of keywords
68
+ * Deprecate move to element with offset changing origin to top left of element
69
+
70
+ 4.1.0 (2021-11-22)
2
71
  =========================
3
72
 
4
73
  DevTools:
data/LICENSE CHANGED
@@ -187,7 +187,7 @@
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright 2021 Software Freedom Conservancy (SFC)
190
+ Copyright 2022 Software Freedom Conservancy (SFC)
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
data/NOTICE CHANGED
@@ -1,2 +1,2 @@
1
- Copyright 2011-2021 Software Freedom Conservancy
1
+ Copyright 2011-2022 Software Freedom Conservancy
2
2
  Copyright 2004-2011 Selenium committers
@@ -84,8 +84,8 @@ module Selenium
84
84
  return download_file_name if File.exist? download_file_name
85
85
 
86
86
  begin
87
- server = 'https://github.com/seleniumhq/selenium/releases/download'
88
- released = Net::HTTP.get_response(URI.parse("#{server}/selenium-#{required_version}/#{download_file_name}"))
87
+ download_location = available_assets[download_file_name]['browser_download_url']
88
+ released = Net::HTTP.get_response(URI.parse(download_location))
89
89
  redirected = URI.parse released.header['location']
90
90
 
91
91
  File.open(download_file_name, 'wb') do |destination|
@@ -105,19 +105,24 @@ module Selenium
105
105
 
106
106
  def latest
107
107
  @latest ||= begin
108
- net_http_start('api.github.com') do |http|
109
- json = http.get('/repos/seleniumhq/selenium/releases').body
110
- all_assets = JSON.parse(json).map { |release| release['assets'] }.flatten
111
- server_assets = all_assets.map { |asset| asset['name'][/selenium-server-(\d+\.\d+\.\d+)\.jar/, 1] }.compact
112
- server_assets.map { |version| Gem::Version.new(version) }.max.version
113
- end
108
+ available = available_assets.keys.map { |key| key[/selenium-server-(\d+\.\d+\.\d+)\.jar/, 1] }
109
+ available.map { |asset| Gem::Version.new(asset) }.max.to_s
114
110
  end
115
111
  end
116
112
 
117
113
  # @api private
118
114
 
115
+ def available_assets
116
+ @available_assets ||= net_http_start('api.github.com') do |http|
117
+ json = http.get('/repos/seleniumhq/selenium/releases').body
118
+ all_assets = JSON.parse(json).map { |release| release['assets'] }.flatten
119
+ server_assets = all_assets.select { |asset| asset['name'].match(/selenium-server-(\d+\.\d+\.\d+)\.jar/) }
120
+ server_assets.each_with_object({}) { |asset, hash| hash[asset.delete('name')] = asset }
121
+ end
122
+ end
123
+
119
124
  def net_http_start(address, &block)
120
- http_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
125
+ http_proxy = ENV.fetch('http_proxy', nil) || ENV.fetch('HTTP_PROXY', nil)
121
126
  if http_proxy
122
127
  http_proxy = "http://#{http_proxy}" unless http_proxy.start_with?('http://')
123
128
  uri = URI.parse(http_proxy)
@@ -0,0 +1,38 @@
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
+ class BiDi
23
+ class Session
24
+ Status = Struct.new(:ready, :message)
25
+
26
+ def initialize(bidi)
27
+ @bidi = bidi
28
+ end
29
+
30
+ def status
31
+ status = @bidi.send_cmd('session.status')
32
+ Status.new(status['ready'], status['message'])
33
+ end
34
+
35
+ end # Session
36
+ end # BiDi
37
+ end # WebDriver
38
+ end # Selenium
@@ -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
+ class BiDi
23
+ autoload :Session, 'selenium/webdriver/bidi/session'
24
+
25
+ def initialize(url:)
26
+ @ws = WebSocketConnection.new(url: url)
27
+ end
28
+
29
+ def close
30
+ @ws.close
31
+ end
32
+
33
+ def callbacks
34
+ @ws.callbacks
35
+ end
36
+
37
+ def session
38
+ Session.new(self)
39
+ end
40
+
41
+ def send_cmd(method, **params)
42
+ data = {method: method, params: params.compact}
43
+ message = @ws.send_cmd(**data)
44
+ raise Error::WebDriverError, error_message(message) if message['error']
45
+
46
+ message['result']
47
+ end
48
+
49
+ def error_message(message)
50
+ "#{message['error']}: #{message['message']}\n#{message['stacktrace']}"
51
+ end
52
+
53
+ end # BiDi
54
+ end # WebDriver
55
+ end # Selenium
@@ -27,6 +27,7 @@ module Selenium
27
27
  get_cast_sinks: [:get, 'session/:session_id/goog/cast/get_sinks'],
28
28
  set_cast_sink_to_use: [:post, 'session/:session_id/goog/cast/set_sink_to_use'],
29
29
  start_cast_tab_mirroring: [:post, 'session/:session_id/goog/cast/start_tab_mirroring'],
30
+ start_cast_desktop_mirroring: [:post, 'session/:session_id/goog/cast/start_desktop_mirroring'],
30
31
  get_cast_issue_message: [:get, 'session/:session_id/goog/cast/get_issue_message'],
31
32
  stop_casting: [:post, 'session/:session_id/goog/cast/stop_casting'],
32
33
  get_network_conditions: [:get, 'session/:session_id/chromium/network_conditions'],
@@ -62,6 +63,10 @@ module Selenium
62
63
  execute :start_cast_tab_mirroring, {}, {sinkName: name}
63
64
  end
64
65
 
66
+ def start_cast_desktop_mirroring(name)
67
+ execute :start_cast_desktop_mirroring, {}, {sinkName: name}
68
+ end
69
+
65
70
  def stop_casting(name)
66
71
  execute :stop_casting, {}, {sinkName: name}
67
72
  end
@@ -52,22 +52,22 @@ module Selenium
52
52
  # options = Selenium::WebDriver::Chrome::Options.new(args: ['start-maximized', 'user-data-dir=/tmp/temp_profile'])
53
53
  # driver = Selenium::WebDriver.for(:chrome, capabilities: options)
54
54
  #
55
- # @param [Profile] :profile An instance of a Chrome::Profile Class
56
- # @param [Array] :encoded_extensions List of extensions that do not need to be Base64 encoded
55
+ # @param [Profile] profile An instance of a Chrome::Profile Class
57
56
  # @param [Hash] opts the pre-defined options to create the Chrome::Options with
58
- # @option opts [Array<String>] :args List of command-line arguments to use when starting Chrome
59
- # @option opts [String] :binary Path to the Chrome executable to use
60
- # @option opts [Hash] :prefs A hash with each entry consisting of the name of the preference and its value
61
- # @option opts [Array<String>] :extensions A list of paths to (.crx) Chrome extensions to install on startup
62
- # @option opts [Hash] :options A hash for raw options
63
- # @option opts [Hash] :emulation A hash for raw emulation options
64
- # @option opts [Hash] :local_state A hash for the Local State file in the user data folder
65
- # @option opts [Boolean] :detach whether browser is closed when the driver is sent the quit command
66
- # @option opts [String] :debugger_address address of a Chrome debugger server to connect to
67
- # @option opts [Array<String>] :exclude_switches command line switches to exclude
68
- # @option opts [String] :minidump_path Directory to store Chrome minidumps (linux only)
69
- # @option opts [Hash] :perf_logging_prefs A hash for performance logging preferences
70
- # @option opts [Array<String>] :window_types A list of window types to appear in the list of window handles
57
+ # @option opts [Array] encoded_extensions List of extensions that do not need to be Base64 encoded
58
+ # @option opts [Array<String>] args List of command-line arguments to use when starting Chrome
59
+ # @option opts [String] binary Path to the Chrome executable to use
60
+ # @option opts [Hash] prefs A hash with each entry consisting of the name of the preference and its value
61
+ # @option opts [Array<String>] extensions A list of paths to (.crx) Chrome extensions to install on startup
62
+ # @option opts [Hash] options A hash for raw options
63
+ # @option opts [Hash] emulation A hash for raw emulation options
64
+ # @option opts [Hash] local_state A hash for the Local State file in the user data folder
65
+ # @option opts [Boolean] detach whether browser is closed when the driver is sent the quit command
66
+ # @option opts [String] debugger_address address of a Chrome debugger server to connect to
67
+ # @option opts [Array<String>] exclude_switches command line switches to exclude
68
+ # @option opts [String] minidump_path Directory to store Chrome minidumps (linux only)
69
+ # @option opts [Hash] perf_logging_prefs A hash for performance logging preferences
70
+ # @option opts [Array<String>] window_types A list of window types to appear in the list of window handles
71
71
  #
72
72
 
73
73
  def initialize(profile: nil, **opts)
@@ -87,7 +87,7 @@ module Selenium
87
87
  @logging_prefs = options.delete(:logging_prefs) || {}
88
88
  @encoded_extensions = @options.delete(:encoded_extensions) || []
89
89
  @extensions = []
90
- (@options.delete(:extensions)).each(&method(:validate_extension))
90
+ @options.delete(:extensions).each { |ext| validate_extension(ext) }
91
91
  end
92
92
 
93
93
  #
@@ -112,11 +112,11 @@ module Selenium
112
112
  # options = Selenium::WebDriver::Chrome::Options.new
113
113
  # options.extensions = extensions
114
114
  #
115
- # @param [Array<String>] :extensions A list of paths to (.crx) Chrome extensions to install on startup
115
+ # @param [Array<String>] extensions A list of paths to (.crx) Chrome extensions to install on startup
116
116
  #
117
117
 
118
118
  def extensions=(extensions)
119
- extensions.each(&method(:validate_extension))
119
+ extensions.each { |ext| validate_extension(ext) }
120
120
  end
121
121
 
122
122
  #
@@ -234,7 +234,7 @@ module Selenium
234
234
 
235
235
  return if (@encoded_extensions + @extensions).empty?
236
236
 
237
- options['extensions'] = @encoded_extensions + @extensions.map(&method(:encode_extension))
237
+ options['extensions'] = @encoded_extensions + @extensions.map { |ext| encode_extension(ext) }
238
238
  end
239
239
 
240
240
  def binary_path
@@ -28,20 +28,6 @@ module Selenium
28
28
  autoload :Options, 'selenium/webdriver/chrome/options'
29
29
  autoload :Service, 'selenium/webdriver/chrome/service'
30
30
 
31
- def self.driver_path=(path)
32
- WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome#driver_path=',
33
- 'Selenium::WebDriver::Chrome::Service#driver_path=',
34
- id: :driver_path
35
- Selenium::WebDriver::Chrome::Service.driver_path = path
36
- end
37
-
38
- def self.driver_path
39
- WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome#driver_path',
40
- 'Selenium::WebDriver::Chrome::Service#driver_path',
41
- id: :driver_path
42
- Selenium::WebDriver::Chrome::Service.driver_path
43
- end
44
-
45
31
  def self.path=(path)
46
32
  Platform.assert_executable path
47
33
  @path = path
@@ -22,6 +22,7 @@ module Selenium
22
22
  class ActionBuilder
23
23
  include KeyActions # Actions specific to key inputs
24
24
  include PointerActions # Actions specific to pointer inputs
25
+ include WheelActions # Actions specific to wheel inputs
25
26
 
26
27
  attr_reader :devices
27
28
 
@@ -31,19 +32,40 @@ module Selenium
31
32
  # the mouse is moving. Keep in mind that pauses must be added for other devices in order to line up the actions
32
33
  # correctly when using asynchronous.
33
34
  #
34
- # @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance
35
- # @param [Selenium::WebDriver::Interactions::PointerInput] mouse PointerInput for the mouse.
36
- # @param [Selenium::WebDriver::Interactions::KeyInput] keyboard KeyInput for the keyboard.
37
- # @param [Boolean] async Whether to perform the actions asynchronously per device. Defaults to false for
38
- # backwards compatibility.
35
+ # @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance.
36
+ # @param [Selenium::WebDriver::Interactions::PointerInput] deprecated_mouse PointerInput for the mouse.
37
+ # @param [Selenium::WebDriver::Interactions::KeyInput] deprecated_keyboard KeyInput for the keyboard.
38
+ # @param [Boolean] deprecated_async Whether to perform the actions asynchronously per device.
39
+ # Defaults to false for backwards compatibility.
40
+ # @param [Array<Selenium::WebDriver::Interactions::InputDevices>] devices list of valid sources of input.
41
+ # @param [Boolean] async Whether to perform the actions asynchronously per device.
39
42
  # @return [ActionBuilder] A self reference.
40
43
  #
41
44
 
42
- def initialize(bridge, mouse, keyboard, async = false)
43
- # For backwards compatibility, automatically include mouse & keyboard
45
+ def initialize(bridge, deprecated_mouse = nil, deprecated_keyboard = nil, deprecated_async = nil,
46
+ devices: [], async: false, duration: 250)
44
47
  @bridge = bridge
45
- @devices = [mouse, keyboard]
46
- @async = async
48
+ @duration = duration
49
+
50
+ @async = if deprecated_async.nil?
51
+ async
52
+ else
53
+ WebDriver.logger.deprecate('initializing ActionBuilder with async parameter',
54
+ ':async keyword',
55
+ id: :action_async)
56
+ deprecated_async
57
+ end
58
+
59
+ @devices = []
60
+ if deprecated_keyboard || deprecated_mouse
61
+ WebDriver.logger.deprecate "initializing ActionBuilder with keyboard and mouse parameters",
62
+ "devices keyword or, even better, Driver#action",
63
+ id: :action_devices
64
+ add_input(deprecated_mouse)
65
+ add_input(deprecated_keyboard)
66
+ else
67
+ Array(devices).each { |device| add_input(device) }
68
+ end
47
69
  end
48
70
 
49
71
  #
@@ -61,9 +83,7 @@ module Selenium
61
83
  #
62
84
 
63
85
  def add_pointer_input(kind, name)
64
- new_input = Interactions.pointer(kind, name: name)
65
- add_input(new_input)
66
- new_input
86
+ add_input(Interactions.pointer(kind, name: name))
67
87
  end
68
88
 
69
89
  #
@@ -79,9 +99,23 @@ module Selenium
79
99
  #
80
100
 
81
101
  def add_key_input(name)
82
- new_input = Interactions.key(name)
83
- add_input(new_input)
84
- new_input
102
+ add_input(Interactions.key(name))
103
+ end
104
+
105
+ #
106
+ # Adds a WheelInput device
107
+ #
108
+ # @example Add a wheel input device
109
+ #
110
+ # builder = device.action
111
+ # builder.add_wheel_input('wheel2')
112
+ #
113
+ # @param [String] name name for the device
114
+ # @return [Interactions::WheelInput] The wheel input added
115
+ #
116
+
117
+ def add_wheel_input(name)
118
+ add_input(Interactions.wheel(name))
85
119
  end
86
120
 
87
121
  #
@@ -92,7 +126,26 @@ module Selenium
92
126
  #
93
127
 
94
128
  def get_device(name)
95
- @devices.find { |device| device.name == name.to_s }
129
+ WebDriver.logger.deprecate('#get_device with name parameter',
130
+ '#device with :name or :type keyword',
131
+ id: :get_device)
132
+ device(name: name)
133
+ end
134
+
135
+ #
136
+ # Retrieves the input device for the given name or type
137
+ #
138
+ # @param [String] name name of the input device
139
+ # @param [String] type name of the input device
140
+ # @return [Selenium::WebDriver::Interactions::InputDevice] input device with given name or type
141
+ #
142
+
143
+ def device(name: nil, type: nil)
144
+ input = @devices.find { |device| (device.name == name.to_s || name.nil?) && (device.type == type || type.nil?) }
145
+
146
+ raise(ArgumentError, "Can not find device: #{name}") if name && input.nil?
147
+
148
+ input
96
149
  end
97
150
 
98
151
  #
@@ -115,6 +168,16 @@ module Selenium
115
168
  @devices.select { |device| device.type == Interactions::KEY }
116
169
  end
117
170
 
171
+ #
172
+ # Retrieves the current WheelInput device
173
+ #
174
+ # @return [Selenium::WebDriver::Interactions::InputDevice] current WheelInput devices
175
+ #
176
+
177
+ def wheel_inputs
178
+ @devices.select { |device| device.type == Interactions::WHEEL }
179
+ end
180
+
118
181
  #
119
182
  # Creates a pause for the given device of the given duration. If no duration is given, the pause will only wait
120
183
  # for all actions to complete in that tick.
@@ -131,8 +194,11 @@ module Selenium
131
194
  # @return [ActionBuilder] A self reference.
132
195
  #
133
196
 
134
- def pause(device, duration = nil)
135
- device.create_pause(duration)
197
+ def pause(deprecated_device = nil, deprecated_duration = nil, device: nil, duration: 0)
198
+ deprecate_method(deprecated_device, deprecated_duration)
199
+
200
+ device ||= deprecated_device || pointer_input
201
+ device.create_pause(deprecated_duration || duration)
136
202
  self
137
203
  end
138
204
 
@@ -152,7 +218,14 @@ module Selenium
152
218
  # @return [ActionBuilder] A self reference.
153
219
  #
154
220
 
155
- def pauses(device, number, duration = nil)
221
+ def pauses(deprecated_device = nil, deprecated_number = nil, deprecated_duration = nil,
222
+ device: nil, number: nil, duration: 0)
223
+ deprecate_method(deprecated_device, deprecated_duration, deprecated_number, method: :pauses)
224
+
225
+ number ||= deprecated_number || 2
226
+ device ||= deprecated_device || pointer_input
227
+ duration ||= deprecated_duration || 0
228
+
156
229
  number.times { device.create_pause(duration) }
157
230
  self
158
231
  end
@@ -162,7 +235,7 @@ module Selenium
162
235
  #
163
236
 
164
237
  def perform
165
- @bridge.send_actions @devices.map(&:encode).compact
238
+ @bridge.send_actions @devices.filter_map(&:encode)
166
239
  clear_all_actions
167
240
  nil
168
241
  end
@@ -202,12 +275,26 @@ module Selenium
202
275
  #
203
276
 
204
277
  def add_input(device)
278
+ device = Interactions.send(device) if device.is_a?(Symbol) && Interactions.respond_to?(device)
279
+
280
+ raise TypeError, "#{device.inspect} is not a valid InputDevice" unless device.is_a?(Interactions::InputDevice)
281
+
205
282
  unless @async
206
283
  max_device = @devices.max { |a, b| a.actions.length <=> b.actions.length }
207
- pauses(device, max_device.actions.length)
284
+ pauses(device: device, number: max_device.actions.length) if max_device
208
285
  end
209
286
  @devices << device
287
+ device
210
288
  end
289
+
290
+ def deprecate_method(device = nil, duration = nil, number = nil, method: :pause)
291
+ return unless device || number || duration
292
+
293
+ WebDriver.logger.deprecate "ActionBuilder##{method} with ordered parameters",
294
+ ':device, :duration, :number keywords',
295
+ id: method
296
+ end
297
+
211
298
  end # ActionBuilder
212
299
  end # WebDriver
213
300
  end # Selenium
@@ -123,8 +123,8 @@ module Selenium
123
123
  # @see ActionBuilder
124
124
  #
125
125
 
126
- def action
127
- bridge.action
126
+ def action(**opts)
127
+ bridge.action(**opts)
128
128
  end
129
129
 
130
130
  def mouse
@@ -307,71 +307,29 @@ module Selenium
307
307
 
308
308
  attr_reader :bridge
309
309
 
310
- def create_bridge(**opts)
311
- opts[:url] ||= service_url(opts)
312
- caps = opts.delete(:capabilities)
313
- # NOTE: This is deprecated
314
- cap_array = caps.is_a?(Hash) ? [caps] : Array(caps)
315
-
316
- desired_capabilities = opts.delete(:desired_capabilities)
317
- if desired_capabilities
318
- WebDriver.logger.deprecate(':desired_capabilities as a parameter for driver initialization',
319
- ':capabilities with an Array value of capabilities/options if necessary',
320
- id: :desired_capabilities)
321
- desired_capabilities = Remote::Capabilities.new(desired_capabilities) if desired_capabilities.is_a?(Hash)
322
- cap_array << desired_capabilities
310
+ def create_bridge(capabilities: nil, options: nil, url: nil, service: nil, http_client: nil)
311
+ Remote::Bridge.new(http_client: http_client,
312
+ url: url || service_url(service)).tap do |bridge|
313
+ generated_caps = options ? options.as_json : generate_capabilities(capabilities)
314
+ bridge.create_session(generated_caps)
323
315
  end
324
-
325
- options = opts.delete(:options)
326
- if options
327
- WebDriver.logger.deprecate(':options as a parameter for driver initialization',
328
- ':capabilities with an Array of value capabilities/options if necessary',
329
- id: :browser_options)
330
- cap_array << options
331
- end
332
-
333
- capabilities = generate_capabilities(cap_array)
334
-
335
- bridge_opts = {http_client: opts.delete(:http_client), url: opts.delete(:url)}
336
- raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
337
-
338
- bridge = Remote::Bridge.new(**bridge_opts)
339
-
340
- bridge.create_session(capabilities)
341
- bridge
342
316
  end
343
317
 
344
- def generate_capabilities(cap_array)
345
- cap_array.map { |cap|
318
+ def generate_capabilities(capabilities)
319
+ Array(capabilities).map { |cap|
346
320
  if cap.is_a? Symbol
347
321
  cap = Remote::Capabilities.send(cap)
348
- elsif cap.is_a? Hash
349
- new_message = 'Capabilities instance initialized with the Hash, or build values with Options class'
350
- WebDriver.logger.deprecate("passing a Hash value to :capabilities",
351
- new_message,
352
- id: :capabilities_hash)
353
- cap = Remote::Capabilities.new(cap)
354
322
  elsif !cap.respond_to? :as_json
355
323
  msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
356
324
  raise ArgumentError, msg
357
325
  end
358
- cap&.as_json
326
+ cap.as_json
359
327
  }.inject(:merge) || Remote::Capabilities.send(browser || :new)
360
328
  end
361
329
 
362
- def service_url(opts)
363
- service_config = opts.delete(:service)
364
- %i[driver_opts driver_path port].each do |key|
365
- next unless opts.key? key
366
-
367
- WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service',
368
- id: "service_#{key}".to_sym)
369
- end
370
- service_config ||= Service.send(browser,
371
- args: opts.delete(:driver_opts),
372
- path: opts.delete(:driver_path),
373
- port: opts.delete(:port))
374
- @service = service_config.launch
330
+ def service_url(service)
331
+ service ||= Service.send(browser)
332
+ @service = service.launch
375
333
  @service.uri
376
334
  end
377
335