selenium-webdriver 4.1.0 → 4.2.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +46 -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/common/action_builder.rb +108 -21
  11. data/lib/selenium/webdriver/common/driver.rb +2 -2
  12. data/lib/selenium/webdriver/common/driver_extensions/has_bidi.rb +38 -0
  13. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -0
  14. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -2
  15. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
  16. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -1
  17. data/lib/selenium/webdriver/common/element.rb +1 -1
  18. data/lib/selenium/webdriver/common/error.rb +1 -1
  19. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  20. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
  21. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  22. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
  23. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  24. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  25. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  26. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +49 -43
  27. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  28. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  29. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  30. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  31. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  32. data/lib/selenium/webdriver/common/interactions/scroll.rb +57 -0
  33. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  34. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  35. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  36. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
  37. data/lib/selenium/webdriver/common/keys.rb +1 -0
  38. data/lib/selenium/webdriver/common/platform.rb +4 -4
  39. data/lib/selenium/webdriver/common/search_context.rb +0 -6
  40. data/lib/selenium/webdriver/common/service_manager.rb +2 -3
  41. data/lib/selenium/webdriver/common/shadow_root.rb +1 -1
  42. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  43. data/lib/selenium/webdriver/common/websocket_connection.rb +149 -0
  44. data/lib/selenium/webdriver/common.rb +14 -2
  45. data/lib/selenium/webdriver/devtools/request.rb +1 -1
  46. data/lib/selenium/webdriver/devtools/response.rb +1 -1
  47. data/lib/selenium/webdriver/devtools.rb +5 -112
  48. data/lib/selenium/webdriver/edge/features.rb +1 -0
  49. data/lib/selenium/webdriver/firefox/driver.rb +1 -0
  50. data/lib/selenium/webdriver/firefox/features.rb +2 -5
  51. data/lib/selenium/webdriver/firefox/options.rb +3 -1
  52. data/lib/selenium/webdriver/firefox/profile.rb +1 -5
  53. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  54. data/lib/selenium/webdriver/firefox.rb +1 -0
  55. data/lib/selenium/webdriver/remote/bridge.rb +21 -19
  56. data/lib/selenium/webdriver/remote/commands.rb +0 -5
  57. data/lib/selenium/webdriver/remote/http/default.rb +6 -12
  58. data/lib/selenium/webdriver/remote/response.rb +2 -2
  59. data/lib/selenium/webdriver/support/cdp_client_generator.rb +4 -4
  60. data/lib/selenium/webdriver/support/color.rb +7 -7
  61. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -1
  62. data/lib/selenium/webdriver/support/guards.rb +1 -1
  63. data/lib/selenium/webdriver/version.rb +1 -1
  64. data/lib/selenium/webdriver.rb +1 -0
  65. data/selenium-webdriver.gemspec +7 -4
  66. metadata +55 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40e4bef1fdee7ae817c56466ec231be400d677d56a8c8f46b797c6b3eba28de9
4
- data.tar.gz: a9c1af31f12db6096f06c2a89e487e40ea2bb53b8f6e46e5f77a3046f149bb34
3
+ metadata.gz: 5767633e16bd3296a248757bd01f157c6441a7780d3bcfd972a7c03f94237d54
4
+ data.tar.gz: 6e82108ff5bd955eeb68e2b7a8e23aa9c766d900f46bbb4e7d3a9475b00a7ceb
5
5
  SHA512:
6
- metadata.gz: b5325d0fe9f5fdb721ed4a6daa1384d7876dc7a072dd52f46c73d76b1614434c123fff2b4a9d7de01538968eddfbad57f2e1a87f4dce0e560a850dcf21988840
7
- data.tar.gz: 3b345ac66d051c32267d1c4ef9b2dd70aea36e2c4e5bb35ce30197d748effca8fed460824d1961ad5a39340358fc9be3f200708a38557e5e878b09be1b0d61c0
6
+ metadata.gz: 792f2a87bb8c1f78c8e7fef7242d9b42026473e9fcb2c8a586e5d1af04188f0026b7b7e0c300b3d9cc3d709a8a7efe0dc6050edd69df1af3b1c397f40a1b0fd8
7
+ data.tar.gz: 840b9619f535ea1f67d603de69d88e5fcf8ca324a9198b68f9e418f1ebde25bae9d40cfda6c65c8fce9321ae21a84b88ef91c57ae99105a95d191dbf28f1f0e5
data/CHANGES CHANGED
@@ -1,4 +1,49 @@
1
- 4.1.0 (2021-11-18)
1
+ 4.2.0 (unreleased)
2
+ =========================
3
+
4
+ BiDi:
5
+ * Released selenium-devtools 0.97.0 (supports CDP v85, v95, v96, v97)
6
+ * Released selenium-devtools 0.98.0 (supports CDP v85, v96, v97, v98)
7
+ * Released selenium-devtools 0.99.0 (supports CDP v85, v97, v98, v99)
8
+ * Released selenium-devtools 0.100.0 (supports CDP v85, v98, v99, v100)
9
+ * Released selenium-devtools 0.101.0 (supports CDP v85, v99, v100, v101)
10
+ * Released selenium-devtools 0.102.0 (supports CDP v85, v100, v101, v102)
11
+ * Implement simple BiDi connection
12
+ * Fix bug in initial BiDi implementation (thanks Boris Petrov!)
13
+ * Fix bug with mutating headers in request interception (#10574)
14
+ * Fix bug with empty response headers (thanks Viren Negi!)
15
+
16
+ Firefox:
17
+ * Add support to Firefox Options for environment capability
18
+ * Use addon parameter instead of path parameter to avoid using file detector
19
+ * Restore #from_name method to Firefox profile (#10146)
20
+
21
+ Chromium:
22
+ * Add support for casting desktop
23
+
24
+ Ruby:
25
+ * Updated minimum required Ruby version to 2.7
26
+ * Fix bug by not attempting to stop service process when it's not started (#10015)
27
+ * Fix bug to not stop service process when it's not started (thanks Atsushi Tatsuma!)
28
+ * Use driver endpoint to get page source instead of JavaScript
29
+ * Add zenkaku_hankaku key support
30
+ * Fix download support of Selenium Server
31
+ * Do not convert Tag Name to CSS Selector
32
+
33
+ ActionBuilder:
34
+ * Raise error if input device not found
35
+ * Move `TypingInteraction` from `Interactions::KeyInput` to `Interactions` module
36
+ * Throw better errors for `PointerInput` methods
37
+ * Allow each action interaction class to validate its own source
38
+ * Set all Interactions classes to private
39
+ * Allow device names to use a default id if one is not specified
40
+ * Deprecate default mouse and keyboard values in constructor, favoring devices parameter
41
+ * Add support for pointer event properties
42
+ * Implement scroll wheel support
43
+ * Deprecate ordered pair parameters for pause method in favor of keywords
44
+ * Deprecate move to element with offset changing origin to top left of element
45
+
46
+ 4.1.0 (2021-11-22)
2
47
  =========================
3
48
 
4
49
  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
@@ -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
@@ -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
+ module DriverExtensions
23
+ module HasBiDi
24
+
25
+ #
26
+ # Retrieves WebDriver BiDi connection.
27
+ #
28
+ # @return [BiDi]
29
+ #
30
+
31
+ def bidi
32
+ @bidi ||= Selenium::WebDriver::BiDi.new(url: capabilities[:web_socket_url])
33
+ end
34
+
35
+ end # HasBiDi
36
+ end # DriverExtensions
37
+ end # WebDriver
38
+ end # Selenium
@@ -52,6 +52,16 @@ module Selenium
52
52
  @bridge.start_cast_tab_mirroring(name)
53
53
  end
54
54
 
55
+ #
56
+ # Starts a tab mirroring session on a specific receiver target.
57
+ #
58
+ # @param [String] name the sink to use as the target
59
+ #
60
+
61
+ def start_cast_desktop_mirroring(name)
62
+ @bridge.start_cast_desktop_mirroring(name)
63
+ end
64
+
55
65
  #
56
66
  # Gets error messages when there is any issue in a Cast session.
57
67
  #
@@ -27,8 +27,7 @@ module Selenium
27
27
  # a `with` statement. The state of the context on the server is
28
28
  # saved before entering the block, and restored upon exiting it.
29
29
  #
30
- # @param [String] name which permission to set
31
- # @param [String] value what to set the permission to
30
+ # @param [String] value which context gets set (either 'chrome' or 'content')
32
31
  #
33
32
 
34
33
  def context=(value)
@@ -114,7 +114,7 @@ module Selenium
114
114
  execute_script(mutation_listener)
115
115
  devtools.page.add_script_to_evaluate_on_new_document(source: mutation_listener)
116
116
 
117
- devtools.runtime.on(:binding_called, &method(:log_mutation_event))
117
+ devtools.runtime.on(:binding_called) { |event| log_mutation_event(event) }
118
118
  end
119
119
 
120
120
  def log_mutation_event(params)
@@ -62,7 +62,7 @@ module Selenium
62
62
  #
63
63
  # Unpins script making it undefined for the subsequent calls.
64
64
  #
65
- # @param [DevTools::PinnedScript]
65
+ # @param [DevTools::PinnedScript] script
66
66
  #
67
67
 
68
68
  def unpin_script(script)
@@ -46,7 +46,7 @@ module Selenium
46
46
  alias_method :eql?, :==
47
47
 
48
48
  def hash
49
- @id.hash ^ @bridge.hash
49
+ [@id, @bridge].hash
50
50
  end
51
51
 
52
52
  #
@@ -29,7 +29,7 @@ module Selenium
29
29
  def self.for_error(error)
30
30
  return if error.nil?
31
31
 
32
- klass_name = error.split(' ').map(&:capitalize).join.sub(/Error$/, '')
32
+ klass_name = error.split.map(&:capitalize).join.sub(/Error$/, '')
33
33
  const_get("#{klass_name}Error", false)
34
34
  rescue NameError
35
35
  WebDriverError