selenium-webdriver 4.0.3 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +64 -0
  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 +20 -20
  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/zipper.rb +3 -1
  45. data/lib/selenium/webdriver/common.rb +14 -2
  46. data/lib/selenium/webdriver/devtools/request.rb +1 -1
  47. data/lib/selenium/webdriver/devtools/response.rb +1 -1
  48. data/lib/selenium/webdriver/devtools.rb +5 -101
  49. data/lib/selenium/webdriver/edge/features.rb +1 -0
  50. data/lib/selenium/webdriver/firefox/driver.rb +1 -0
  51. data/lib/selenium/webdriver/firefox/features.rb +2 -5
  52. data/lib/selenium/webdriver/firefox/options.rb +4 -2
  53. data/lib/selenium/webdriver/firefox/profile.rb +1 -5
  54. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  55. data/lib/selenium/webdriver/firefox.rb +1 -0
  56. data/lib/selenium/webdriver/ie/options.rb +2 -2
  57. data/lib/selenium/webdriver/remote/bridge.rb +24 -19
  58. data/lib/selenium/webdriver/remote/commands.rb +0 -5
  59. data/lib/selenium/webdriver/remote/http/default.rb +6 -12
  60. data/lib/selenium/webdriver/remote/response.rb +2 -2
  61. data/lib/selenium/webdriver/remote.rb +6 -5
  62. data/lib/selenium/webdriver/support/cdp_client_generator.rb +4 -4
  63. data/lib/selenium/webdriver/support/color.rb +7 -7
  64. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -1
  65. data/lib/selenium/webdriver/support/guards.rb +1 -1
  66. data/lib/selenium/webdriver/version.rb +1 -1
  67. data/lib/selenium/webdriver.rb +2 -1
  68. data/selenium-webdriver.gemspec +7 -4
  69. metadata +55 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7038d1d04e32c0eab2f4081b63161c315afcec139a1d2b45109e41852792f9b5
4
- data.tar.gz: 5208af4b04d474558411a77a25c7150a1274a9123f4ceb3d50a4db7cd5656c2e
3
+ metadata.gz: 16d699e79466a2c8a00b7366541095880a570f21bc749523f5d55283cbd0b9a0
4
+ data.tar.gz: 88d1396b5a026321de780a63b9333e5f9b9332570697049ac3e55ec097970b51
5
5
  SHA512:
6
- metadata.gz: 1896dab6cb8b33ffe30a042829f118526709c2e45e933ad299e4370ab2a1f97263fda23183fc0e7ccce34ee2b1e131427b98919c573fd1c192d681cfc05fc740
7
- data.tar.gz: 95da54a1ad17e54cdb08689c9fc148993b8e405a86319f8ed8ca4b49e00935de5182ea28e67a4987c7eb7671ffc9d4467062bf51fe0ae2c1fd798c317b765f1c
6
+ metadata.gz: 640c3f5921c1a9abb971cc0a90fd7a6053ac8806de54d7b8fbd35c19a066202ca9da0da3e43b01d81e8fe0adcbba72b0b616d14f5289f29da45c9fab7a20d919
7
+ data.tar.gz: 0b261c01d7e2e3c54b8097e714932a923331fa25d30c7c970dd576dc9e0e44782ef9cb6dac1221ce209fd3e03ca7a241143ddba428468e97de21802360c82f21
data/CHANGES CHANGED
@@ -1,3 +1,67 @@
1
+ 4.2.1 (2022-05-31)
2
+ =========================
3
+
4
+ Ruby
5
+ * Fix bug in setting default duration in Actions constructor
6
+
7
+ 4.2.0 (2022-05-27)
8
+ =========================
9
+
10
+ BiDi:
11
+ * Released selenium-devtools 0.97.0 (supports CDP v85, v95, v96, v97)
12
+ * Released selenium-devtools 0.98.0 (supports CDP v85, v96, v97, v98)
13
+ * Released selenium-devtools 0.99.0 (supports CDP v85, v97, v98, v99)
14
+ * Released selenium-devtools 0.100.0 (supports CDP v85, v98, v99, v100)
15
+ * Released selenium-devtools 0.101.0 (supports CDP v85, v99, v100, v101)
16
+ * Released selenium-devtools 0.102.0 (supports CDP v85, v100, v101, v102)
17
+ * Implement simple BiDi connection
18
+ * Fix bug in initial BiDi implementation (thanks Boris Petrov!)
19
+ * Fix bug with mutating headers in request interception (#10574)
20
+ * Fix bug with empty response headers (thanks Viren Negi!)
21
+
22
+ Firefox:
23
+ * Add support to Firefox Options for environment capability
24
+ * Use addon parameter instead of path parameter to avoid using file detector
25
+ * Restore #from_name method to Firefox profile (#10146)
26
+
27
+ Chromium:
28
+ * Add support for casting desktop
29
+
30
+ Ruby:
31
+ * Updated minimum required Ruby version to 2.7
32
+ * Fix bug by not attempting to stop service process when it's not started (#10015)
33
+ * Fix bug to not stop service process when it's not started (thanks Atsushi Tatsuma!)
34
+ * Use driver endpoint to get page source instead of JavaScript
35
+ * Add zenkaku_hankaku key support
36
+ * Fix download support of Selenium Server
37
+ * Do not convert Tag Name to CSS Selector
38
+
39
+ ActionBuilder:
40
+ * Raise error if input device not found
41
+ * Move `TypingInteraction` from `Interactions::KeyInput` to `Interactions` module
42
+ * Throw better errors for `PointerInput` methods
43
+ * Allow each action interaction class to validate its own source
44
+ * Set all Interactions classes to private
45
+ * Allow device names to use a default id if one is not specified
46
+ * Deprecate default mouse and keyboard values in constructor, favoring devices parameter
47
+ * Add support for pointer event properties
48
+ * Implement scroll wheel support
49
+ * Deprecate ordered pair parameters for pause method in favor of keywords
50
+ * Deprecate move to element with offset changing origin to top left of element
51
+
52
+ 4.1.0 (2021-11-22)
53
+ =========================
54
+
55
+ DevTools:
56
+ * Released selenium-devtools 0.95.0 (supports CDP v85, v93, v94, v95)
57
+ * Released selenium-devtools 0.96.0 (supports CDP v85, v94, v95, v96)
58
+ * Added support for secure websockets (#10017)
59
+
60
+ Ruby:
61
+ * Execute Script supports ShadowRoots (#10019)
62
+ * Fixed bug preventing zipping temp files on Windows (#9987)
63
+ * Sang Pumpkin Carol (thanks Jari!)
64
+
1
65
  4.0.3 (2021-10-20)
2
66
  =========================
3
67
 
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
@@ -50,24 +50,24 @@ module Selenium
50
50
  #
51
51
  # @example
52
52
  # options = Selenium::WebDriver::Chrome::Options.new(args: ['start-maximized', 'user-data-dir=/tmp/temp_profile'])
53
- # driver = Selenium::WebDriver.for(:chrome, options: options)
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