selenium-webdriver 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
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