selenium-webdriver 4.1.0 → 4.28.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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +446 -1
  3. data/Gemfile +4 -0
  4. data/LICENSE +1 -1
  5. data/NOTICE +1 -1
  6. data/README.md +3 -3
  7. data/bin/linux/selenium-manager +0 -0
  8. data/bin/macos/selenium-manager +0 -0
  9. data/bin/windows/selenium-manager.exe +0 -0
  10. data/lib/selenium/server.rb +41 -43
  11. data/lib/selenium/webdriver/atoms/findElements.js +52 -50
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +6 -100
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +24 -96
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
  15. data/lib/selenium/webdriver/atoms.rb +5 -3
  16. data/lib/selenium/webdriver/bidi/browsing_context.rb +100 -0
  17. data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
  18. data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
  19. data/lib/selenium/webdriver/{common/driver_extensions/has_location.rb → bidi/log/filter_by.rb} +14 -11
  20. data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
  21. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
  22. data/lib/selenium/webdriver/bidi/log_handler.rb +65 -0
  23. data/lib/selenium/webdriver/bidi/log_inspector.rb +147 -0
  24. data/lib/selenium/webdriver/bidi/network.rb +82 -0
  25. data/lib/selenium/webdriver/bidi/session.rb +51 -0
  26. data/lib/selenium/webdriver/bidi/struct.rb +42 -0
  27. data/lib/selenium/webdriver/bidi.rb +67 -0
  28. data/lib/selenium/webdriver/chrome/driver.rb +9 -29
  29. data/lib/selenium/webdriver/chrome/features.rb +9 -67
  30. data/lib/selenium/webdriver/chrome/options.rb +3 -223
  31. data/lib/selenium/webdriver/chrome/profile.rb +3 -83
  32. data/lib/selenium/webdriver/chrome/service.rb +5 -19
  33. data/lib/selenium/webdriver/chrome.rb +0 -16
  34. data/lib/selenium/webdriver/chromium/driver.rb +61 -0
  35. data/lib/selenium/webdriver/chromium/features.rb +99 -0
  36. data/lib/selenium/webdriver/chromium/options.rb +243 -0
  37. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  38. data/lib/selenium/webdriver/chromium.rb +29 -0
  39. data/lib/selenium/webdriver/common/action_builder.rb +60 -22
  40. data/lib/selenium/webdriver/common/child_process.rb +136 -0
  41. data/lib/selenium/webdriver/common/driver.rb +54 -89
  42. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  43. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
  44. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
  46. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
  47. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +10 -5
  48. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -1
  49. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
  50. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -4
  51. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
  53. data/lib/selenium/webdriver/common/driver_extensions/has_fedcm_dialog.rb +55 -0
  54. data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +65 -0
  55. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
  56. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +9 -3
  57. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
  58. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +8 -68
  59. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
  60. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -3
  61. data/lib/selenium/webdriver/common/driver_finder.rb +97 -0
  62. data/lib/selenium/webdriver/common/element.rb +8 -8
  63. data/lib/selenium/webdriver/common/error.rb +29 -4
  64. data/lib/selenium/webdriver/common/fedcm/account.rb +49 -0
  65. data/lib/selenium/webdriver/common/fedcm/dialog.rb +74 -0
  66. data/lib/selenium/webdriver/common/fedcm.rb +27 -0
  67. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  68. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  69. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
  70. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  71. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
  72. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  73. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  74. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  75. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -71
  76. data/lib/selenium/webdriver/common/{driver_extensions/has_network_connection.rb → interactions/pointer_cancel.rb} +19 -11
  77. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  78. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  79. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  80. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  81. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  82. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  83. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  84. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +114 -0
  85. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
  86. data/lib/selenium/webdriver/common/keys.rb +1 -0
  87. data/lib/selenium/webdriver/common/local_driver.rb +53 -0
  88. data/lib/selenium/webdriver/common/logger.rb +93 -28
  89. data/lib/selenium/webdriver/common/manager.rb +2 -29
  90. data/lib/selenium/webdriver/common/network.rb +64 -0
  91. data/lib/selenium/webdriver/common/options.rb +19 -19
  92. data/lib/selenium/webdriver/common/platform.rb +12 -52
  93. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  94. data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
  95. data/lib/selenium/webdriver/common/proxy.rb +4 -4
  96. data/lib/selenium/webdriver/common/script.rb +45 -0
  97. data/lib/selenium/webdriver/common/search_context.rb +10 -8
  98. data/lib/selenium/webdriver/common/selenium_manager.rb +104 -0
  99. data/lib/selenium/webdriver/common/service.rb +24 -26
  100. data/lib/selenium/webdriver/common/service_manager.rb +9 -15
  101. data/lib/selenium/webdriver/common/shadow_root.rb +2 -3
  102. data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
  103. data/lib/selenium/webdriver/common/socket_poller.rb +3 -3
  104. data/lib/selenium/webdriver/common/takes_screenshot.rb +6 -5
  105. data/lib/selenium/webdriver/common/target_locator.rb +5 -5
  106. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  107. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  108. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  109. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  110. data/lib/selenium/webdriver/common/wait.rb +1 -1
  111. data/lib/selenium/webdriver/common/websocket_connection.rb +176 -0
  112. data/lib/selenium/webdriver/common/window.rb +6 -6
  113. data/lib/selenium/webdriver/common/zipper.rb +1 -1
  114. data/lib/selenium/webdriver/common.rb +27 -5
  115. data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
  116. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
  117. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
  118. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  119. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
  120. data/lib/selenium/webdriver/devtools/request.rb +1 -3
  121. data/lib/selenium/webdriver/devtools/response.rb +1 -3
  122. data/lib/selenium/webdriver/devtools.rb +17 -114
  123. data/lib/selenium/webdriver/edge/driver.rb +9 -3
  124. data/lib/selenium/webdriver/edge/features.rb +8 -4
  125. data/lib/selenium/webdriver/edge/options.rb +17 -5
  126. data/lib/selenium/webdriver/edge/profile.rb +2 -2
  127. data/lib/selenium/webdriver/edge/service.rb +8 -7
  128. data/lib/selenium/webdriver/edge.rb +0 -2
  129. data/lib/selenium/webdriver/firefox/driver.rb +9 -2
  130. data/lib/selenium/webdriver/firefox/features.rb +11 -7
  131. data/lib/selenium/webdriver/firefox/options.rb +10 -16
  132. data/lib/selenium/webdriver/firefox/profile.rb +21 -17
  133. data/lib/selenium/webdriver/firefox/profiles_ini.rb +1 -1
  134. data/lib/selenium/webdriver/firefox/service.rb +1 -18
  135. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  136. data/lib/selenium/webdriver/firefox.rb +1 -14
  137. data/lib/selenium/webdriver/ie/driver.rb +7 -1
  138. data/lib/selenium/webdriver/ie/features.rb +34 -0
  139. data/lib/selenium/webdriver/ie/options.rb +6 -4
  140. data/lib/selenium/webdriver/ie/service.rb +1 -22
  141. data/lib/selenium/webdriver/ie.rb +4 -17
  142. data/lib/selenium/webdriver/remote/bidi_bridge.rb +66 -0
  143. data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +22 -9
  144. data/lib/selenium/webdriver/remote/bridge/locator_converter.rb +76 -0
  145. data/lib/selenium/webdriver/remote/bridge.rb +158 -100
  146. data/lib/selenium/webdriver/remote/capabilities.rb +5 -55
  147. data/lib/selenium/webdriver/remote/driver.rb +35 -14
  148. data/lib/selenium/webdriver/remote/features.rb +75 -0
  149. data/lib/selenium/webdriver/remote/http/common.rb +26 -6
  150. data/lib/selenium/webdriver/remote/http/curb.rb +10 -6
  151. data/lib/selenium/webdriver/remote/http/default.rb +8 -14
  152. data/lib/selenium/webdriver/remote/response.rb +14 -22
  153. data/lib/selenium/webdriver/remote/server_error.rb +2 -2
  154. data/lib/selenium/webdriver/remote.rb +3 -2
  155. data/lib/selenium/webdriver/safari/driver.rb +7 -1
  156. data/lib/selenium/webdriver/safari/features.rb +5 -3
  157. data/lib/selenium/webdriver/safari/options.rb +5 -1
  158. data/lib/selenium/webdriver/safari/service.rb +10 -4
  159. data/lib/selenium/webdriver/safari.rb +1 -15
  160. data/lib/selenium/webdriver/support/color.rb +22 -22
  161. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  162. data/lib/selenium/webdriver/support/guards/guard.rb +14 -14
  163. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -3
  164. data/lib/selenium/webdriver/support/guards.rb +4 -4
  165. data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
  166. data/lib/selenium/webdriver/support/select.rb +3 -1
  167. data/lib/selenium/webdriver/version.rb +1 -1
  168. data/lib/selenium/webdriver.rb +7 -5
  169. data/selenium-webdriver.gemspec +22 -16
  170. metadata +137 -47
  171. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
  172. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
  173. data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
@@ -20,17 +20,18 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Interactions
23
+ #
24
+ # Creates actions specific to Key Input devices
25
+ #
26
+ # @api private
27
+ #
28
+
23
29
  class KeyInput < InputDevice
24
30
  SUBTYPES = {down: :keyDown, up: :keyUp, pause: :pause}.freeze
25
31
 
26
- def type
27
- Interactions::KEY
28
- end
29
-
30
- def encode
31
- return nil if no_actions?
32
-
33
- {type: type, id: name, actions: @actions.map(&:encode)}
32
+ def initialize(name = nil)
33
+ super
34
+ @type = Interactions::KEY
34
35
  end
35
36
 
36
37
  def create_key_down(key)
@@ -41,25 +42,8 @@ module Selenium
41
42
  add_action(TypingInteraction.new(self, :up, key))
42
43
  end
43
44
 
44
- class TypingInteraction < Interaction
45
- attr_reader :type
46
-
47
- def initialize(source, type, key)
48
- super(source)
49
- @type = assert_type(type)
50
- @key = Keys.encode_key(key)
51
- end
52
-
53
- def assert_type(type)
54
- raise TypeError, "#{type.inspect} is not a valid key subtype" unless KeyInput::SUBTYPES.key? type
55
-
56
- KeyInput::SUBTYPES[type]
57
- end
58
-
59
- def encode
60
- {type: @type, value: @key}
61
- end
62
- end # TypingInteraction
45
+ # Backward compatibility in case anyone called this directly
46
+ class TypingInteraction < Interactions::TypingInteraction; end
63
47
  end # KeyInput
64
48
  end # Interactions
65
49
  end # WebDriver
@@ -20,15 +20,17 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Interactions
23
- class NoneInput < InputDevice
24
- def type
25
- Interactions::NONE
26
- end
23
+ #
24
+ # Creates actions specific to null input source
25
+ # This is primarily used for adding pauses
26
+ #
27
+ # @api private
28
+ #
27
29
 
28
- def encode
29
- return nil if no_actions?
30
-
31
- {type: type, id: name, actions: @actions.map(&:encode)}
30
+ class NoneInput < InputDevice
31
+ def initialize(name = nil)
32
+ super
33
+ @type = Interactions::NONE
32
34
  end
33
35
  end # NoneInput
34
36
  end # Interactions
@@ -0,0 +1,49 @@
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 Interactions
23
+ #
24
+ # Action to create a waiting period between actions
25
+ # Also used for synchronizing actions across devices
26
+ #
27
+ # @api private
28
+ #
29
+
30
+ class Pause < Interaction
31
+ def initialize(source, duration = nil)
32
+ super(source)
33
+ @duration = duration
34
+ @type = :pause
35
+ end
36
+
37
+ def assert_source(source)
38
+ raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? InputDevice
39
+ end
40
+
41
+ def encode
42
+ output = {type: type}
43
+ output[:duration] = (@duration * 1000).to_i if @duration
44
+ output
45
+ end
46
+ end # Pause
47
+ end # Interactions
48
+ end # WebDriver
49
+ end # Selenium
@@ -23,11 +23,12 @@ module Selenium
23
23
  attr_writer :default_move_duration
24
24
 
25
25
  #
26
- # The overridable duration for movement used by methods in this module
26
+ # By default this is set to 250ms in the ActionBuilder constructor
27
+ # It can be overridden with default_move_duration=
27
28
  #
28
29
 
29
30
  def default_move_duration
30
- @default_move_duration ||= 0.25 # 250 milliseconds
31
+ @default_move_duration ||= @duration / 1000.0 # convert ms to seconds
31
32
  end
32
33
 
33
34
  #
@@ -45,8 +46,8 @@ module Selenium
45
46
  # @return [ActionBuilder] A self reference.
46
47
  #
47
48
 
48
- def pointer_down(button, device: nil)
49
- button_action(button, action: :create_pointer_down, device: device)
49
+ def pointer_down(button = :left, device: nil, **opts)
50
+ button_action(button, :create_pointer_down, device: device, **opts)
50
51
  end
51
52
 
52
53
  #
@@ -62,21 +63,20 @@ module Selenium
62
63
  # @return [ActionBuilder] A self reference.
63
64
  #
64
65
 
65
- def pointer_up(button, device: nil)
66
- button_action(button, action: :create_pointer_up, device: device)
66
+ def pointer_up(button = :left, device: nil, **opts)
67
+ button_action(button, :create_pointer_up, device: device, **opts)
67
68
  end
68
69
 
69
70
  #
70
- # Moves the mouse to the middle of the given element. The element is scrolled into
71
- # view and its location is calculated using getBoundingClientRect. Then the
72
- # mouse is moved to optional offset coordinates from the element.
71
+ # Moves the pointer to the in-view center point of the given element.
72
+ # Then the pointer is moved to optional offset coordinates.
73
73
  #
74
- # This is adapted to be backward compatible from non- actions. calculates offset from the center point
75
- # of the element
74
+ # The element is not scrolled into view.
75
+ # MoveTargetOutOfBoundsError will be raised if element with offset is outside the viewport
76
76
  #
77
- # Note that when using offsets, both coordinates need to be passed.
77
+ # When using offsets, both coordinates need to be passed.
78
78
  #
79
- # @example Scroll element into view and move the mouse to it
79
+ # @example Move the pointer to element
80
80
  #
81
81
  # el = driver.find_element(id: "some_id")
82
82
  # driver.action.move_to(el).perform
@@ -87,69 +87,59 @@ module Selenium
87
87
  # driver.action.move_to(el, 100, 100).perform
88
88
  #
89
89
  # @param [Selenium::WebDriver::Element] element to move to.
90
- # @param [Integer] right_by Optional offset from the top-left corner. A negative value means
91
- # coordinates to the left of the element.
92
- # @param [Integer] down_by Optional offset from the top-left corner. A negative value means
93
- # coordinates above the element.
94
- # @param [Symbol || String] device optional name of the PointerInput device to move.
90
+ # @param [Integer] right_by Optional offset from the in-view center of the
91
+ # element. A negative value means coordinates to the left of the center.
92
+ # @param [Integer] down_by Optional offset from the in-view center of the
93
+ # element. A negative value means coordinates to the top of the center.
95
94
  # @return [ActionBuilder] A self reference.
96
95
  #
97
96
 
98
- def move_to(element, right_by = nil, down_by = nil, device: nil)
99
- pointer = get_pointer(device)
100
- # New actions offset is from center of element
101
- if right_by || down_by
102
- size = element.size
103
- left_offset = (size[:width] / 2).to_i
104
- top_offset = (size[:height] / 2).to_i
105
- left = -left_offset + (right_by || 0)
106
- top = -top_offset + (down_by || 0)
107
- else
108
- left = 0
109
- top = 0
110
- end
111
- pointer.create_pointer_move(duration: default_move_duration,
112
- x: left,
113
- y: top,
114
- element: element)
97
+ def move_to(element, right_by = nil, down_by = nil, **opts)
98
+ pointer = pointer_input(opts.delete(:device))
99
+ pointer.create_pointer_move(duration: opts.delete(:duration) || default_move_duration,
100
+ x: right_by || 0,
101
+ y: down_by || 0,
102
+ origin: element,
103
+ **opts)
115
104
  tick(pointer)
116
105
  self
117
106
  end
118
107
 
119
108
  #
120
- # Moves the mouse from its current position by the given offset.
121
- # If the coordinates provided are outside the viewport (the mouse will
122
- # end up outside the browser window) then the viewport is scrolled to
123
- # match.
109
+ # Moves the pointer from its current position by the given offset.
124
110
  #
125
- # @example Move the mouse to a certain offset from its current position
111
+ # The viewport is not scrolled if the coordinates provided are outside the viewport.
112
+ # MoveTargetOutOfBoundsError will be raised if the offsets are outside the viewport
113
+ #
114
+ # @example Move the pointer to a certain offset from its current position
126
115
  #
127
116
  # driver.action.move_by(100, 100).perform
128
117
  #
129
- # @param [Integer] right_by horizontal offset. A negative value means moving the mouse left.
130
- # @param [Integer] down_by vertical offset. A negative value means moving the mouse up.
118
+ # @param [Integer] right_by horizontal offset. A negative value means moving the pointer left.
119
+ # @param [Integer] down_by vertical offset. A negative value means moving the pointer up.
131
120
  # @param [Symbol || String] device optional name of the PointerInput device to move
132
121
  # @return [ActionBuilder] A self reference.
133
122
  # @raise [MoveTargetOutOfBoundsError] if the provided offset is outside the document's boundaries.
134
123
  #
135
124
 
136
- def move_by(right_by, down_by, device: nil)
137
- pointer = get_pointer(device)
138
- pointer.create_pointer_move(duration: default_move_duration,
125
+ def move_by(right_by, down_by, device: nil, duration: default_move_duration, **opts)
126
+ pointer = pointer_input(device)
127
+ pointer.create_pointer_move(duration: duration,
139
128
  x: Integer(right_by),
140
129
  y: Integer(down_by),
141
- origin: Interactions::PointerMove::POINTER)
130
+ origin: Interactions::PointerMove::POINTER,
131
+ **opts)
142
132
  tick(pointer)
143
133
  self
144
134
  end
145
135
 
146
136
  #
147
- # Moves the mouse to a given location in the viewport.
148
- # If the coordinates provided are outside the viewport (the mouse will
149
- # end up outside the browser window) then the viewport is scrolled to
150
- # match.
137
+ # Moves the pointer to a given location in the viewport.
138
+ #
139
+ # The viewport is not scrolled if the coordinates provided are outside the viewport.
140
+ # MoveTargetOutOfBoundsError will be raised if the offsets are outside the viewport
151
141
  #
152
- # @example Move the mouse to a certain position in the viewport
142
+ # @example Move the pointer to a certain position in the viewport
153
143
  #
154
144
  # driver.action.move_to_location(100, 100).perform
155
145
  #
@@ -160,12 +150,13 @@ module Selenium
160
150
  # @raise [MoveTargetOutOfBoundsError] if the provided x or y value is outside the document's boundaries.
161
151
  #
162
152
 
163
- def move_to_location(x, y, device: nil)
164
- pointer = get_pointer(device)
165
- pointer.create_pointer_move(duration: default_move_duration,
153
+ def move_to_location(x, y, device: nil, duration: default_move_duration, **opts)
154
+ pointer = pointer_input(device)
155
+ pointer.create_pointer_move(duration: duration,
166
156
  x: Integer(x),
167
157
  y: Integer(y),
168
- origin: Interactions::PointerMove::VIEWPORT)
158
+ origin: Interactions::PointerMove::VIEWPORT,
159
+ **opts)
169
160
  tick(pointer)
170
161
  self
171
162
  end
@@ -186,9 +177,9 @@ module Selenium
186
177
  # @return [ActionBuilder] A self reference.
187
178
  #
188
179
 
189
- def click_and_hold(element = nil, device: nil)
180
+ def click_and_hold(element = nil, button: nil, device: nil)
190
181
  move_to(element, device: device) if element
191
- pointer_down(:left, device: device)
182
+ pointer_down(button || :left, device: device)
192
183
  self
193
184
  end
194
185
 
@@ -205,8 +196,8 @@ module Selenium
205
196
  # @return [ActionBuilder] A self reference.
206
197
  #
207
198
 
208
- def release(device: nil)
209
- pointer_up(:left, device: device)
199
+ def release(button: nil, device: nil)
200
+ pointer_up(button || :left, device: device)
210
201
  self
211
202
  end
212
203
 
@@ -232,10 +223,10 @@ module Selenium
232
223
  # @return [ActionBuilder] A self reference.
233
224
  #
234
225
 
235
- def click(element = nil, device: nil)
226
+ def click(element = nil, button: nil, device: nil)
236
227
  move_to(element, device: device) if element
237
- pointer_down(:left, device: device)
238
- pointer_up(:left, device: device)
228
+ pointer_down(button || :left, device: device)
229
+ pointer_up(button || :left, device: device)
239
230
  self
240
231
  end
241
232
 
@@ -290,10 +281,7 @@ module Selenium
290
281
  #
291
282
 
292
283
  def context_click(element = nil, device: nil)
293
- move_to(element, device: device) if element
294
- pointer_down(:right, device: device)
295
- pointer_up(:right, device: device)
296
- self
284
+ click(element, button: :right, device: device)
297
285
  end
298
286
 
299
287
  #
@@ -348,15 +336,15 @@ module Selenium
348
336
 
349
337
  private
350
338
 
351
- def button_action(button, action: nil, device: nil)
352
- pointer = get_pointer(device)
353
- pointer.send(action, button)
339
+ def button_action(button, action, device: nil, **opts)
340
+ pointer = pointer_input(device)
341
+ pointer.send(action, button, **opts)
354
342
  tick(pointer)
355
343
  self
356
344
  end
357
345
 
358
- def get_pointer(device = nil)
359
- get_device(device) || pointer_inputs.first
346
+ def pointer_input(name = nil)
347
+ device(name: name, type: Interactions::POINTER) || add_pointer_input(:mouse, 'mouse')
360
348
  end
361
349
  end # PointerActions
362
350
  end # WebDriver
@@ -17,21 +17,29 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- # TODO: Deprecated; Delete after 4.0 release
21
20
  module Selenium
22
21
  module WebDriver
23
- module DriverExtensions
24
- module HasNetworkConnection
25
- def network_connection_type
26
- raise Error::UnsupportedOperationError,
27
- 'The W3C standard does not currently support getting network connection'
22
+ module Interactions
23
+ #
24
+ # Action to cancel any other Pointer Action.
25
+ #
26
+ # @api private
27
+ #
28
+
29
+ class PointerCancel < Interaction
30
+ def initialize(source)
31
+ super
32
+ @type = :pointerCancel
33
+ end
34
+
35
+ def assert_source(source)
36
+ raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? PointerInput
28
37
  end
29
38
 
30
- def network_connection_type=(*)
31
- raise Error::UnsupportedOperationError,
32
- 'The W3C standard does not currently support setting network connection'
39
+ def encode
40
+ {type: type}
33
41
  end
34
- end # HasNetworkConnection
35
- end # DriverExtensions
42
+ end # PointerCancel
43
+ end # Interactions
36
44
  end # WebDriver
37
45
  end # Selenium
@@ -0,0 +1,63 @@
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 Interactions
23
+ module PointerEventProperties
24
+ VALID = {width: {'width' => {min: 0.0}},
25
+ height: {'height' => {min: 0.0}},
26
+ pressure: {'pressure' => {min: 0.0, max: 1.0}},
27
+ tangential_pressure: {'tangentialPressure' => {min: -1.0, max: 1.0}},
28
+ tilt_x: {'tiltX' => {min: -90, max: 90}},
29
+ tilt_y: {'tiltY' => {min: -90, max: 90}},
30
+ twist: {'twist' => {min: 0, max: 359}},
31
+ altitude_angle: {'altitudeAngle' => {min: 0.0, max: (Math::PI / 2)}},
32
+ azimuth_angle: {'azimuthAngle' => {min: 0.0, max: (Math::PI * 2)}}}.freeze
33
+
34
+ def process_opts
35
+ raise ArgumentError, "Unknown options found: #{@opts.inspect}" unless (@opts.keys - VALID.keys).empty?
36
+
37
+ VALID.each_with_object({}) do |(key, val), hash|
38
+ next unless @opts.key?(key)
39
+
40
+ name = val.keys.first
41
+ values = val.values.first
42
+ hash[name] = assert_number(@opts[key], values[:min], values[:max])
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def assert_number(num, min, max = nil)
49
+ return if num.nil?
50
+
51
+ klass = min.is_a?(Integer) ? Integer : Numeric
52
+ raise TypeError, "#{num} is not a #{klass}" unless num.is_a?(klass)
53
+
54
+ raise ArgumentError, "#{num} is not greater than or equal to #{min}" if num < min
55
+
56
+ raise ArgumentError, "#{num} is not less than or equal to #{max}" if max && num > max
57
+
58
+ num
59
+ end
60
+ end # PointerEventProperties
61
+ end # Interactions
62
+ end # WebDriver
63
+ end # Selenium
@@ -20,6 +20,12 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Interactions
23
+ #
24
+ # Creates actions specific to Pointer Input devices
25
+ #
26
+ # @api private
27
+ #
28
+
23
29
  class PointerInput < InputDevice
24
30
  KIND = {mouse: :mouse, pen: :pen, touch: :touch}.freeze
25
31
 
@@ -28,17 +34,12 @@ module Selenium
28
34
  def initialize(kind, name: nil)
29
35
  super(name)
30
36
  @kind = assert_kind(kind)
31
- end
32
-
33
- def type
34
- Interactions::POINTER
37
+ @type = Interactions::POINTER
35
38
  end
36
39
 
37
40
  def encode
38
- return nil if no_actions?
39
-
40
- output = {type: type, id: name, actions: @actions.map(&:encode)}
41
- output[:parameters] = {pointerType: kind}
41
+ output = super
42
+ output[:parameters] = {pointerType: kind} if output
42
43
  output
43
44
  end
44
45
 
@@ -48,92 +49,22 @@ module Selenium
48
49
  KIND[pointer]
49
50
  end
50
51
 
51
- def create_pointer_move(duration: 0, x: 0, y: 0, element: nil, origin: nil)
52
- add_action(PointerMove.new(self, duration, x, y, element: element, origin: origin))
52
+ def create_pointer_move(duration: 0, x: 0, y: 0, origin: nil, **opts)
53
+ add_action(PointerMove.new(self, duration, x, y, origin: origin, **opts))
53
54
  end
54
55
 
55
- def create_pointer_down(button)
56
- add_action(PointerPress.new(self, :down, button))
56
+ def create_pointer_down(button, **opts)
57
+ add_action(PointerPress.new(self, :down, button, **opts))
57
58
  end
58
59
 
59
- def create_pointer_up(button)
60
- add_action(PointerPress.new(self, :up, button))
60
+ def create_pointer_up(button, **opts)
61
+ add_action(PointerPress.new(self, :up, button, **opts))
61
62
  end
62
63
 
63
64
  def create_pointer_cancel
64
65
  add_action(PointerCancel.new(self))
65
66
  end
66
67
  end # PointerInput
67
-
68
- class PointerPress < Interaction
69
- BUTTONS = {left: 0, middle: 1, right: 2}.freeze
70
- DIRECTIONS = {down: :pointerDown, up: :pointerUp}.freeze
71
-
72
- def initialize(source, direction, button)
73
- super(source)
74
- @direction = assert_direction(direction)
75
- @button = assert_button(button)
76
- end
77
-
78
- def type
79
- @direction
80
- end
81
-
82
- def assert_button(button)
83
- if button.is_a? Symbol
84
- raise TypeError, "#{button.inspect} is not a valid button!" unless BUTTONS.key? button
85
-
86
- button = BUTTONS[button]
87
- end
88
- raise ArgumentError, 'Button number cannot be negative!' unless button >= 0
89
-
90
- button
91
- end
92
-
93
- def assert_direction(direction)
94
- raise TypeError, "#{direction.inspect} is not a valid button direction" unless DIRECTIONS.key? direction
95
-
96
- DIRECTIONS[direction]
97
- end
98
-
99
- def encode
100
- {type: type, button: @button}
101
- end
102
- end # PointerPress
103
-
104
- class PointerMove < Interaction
105
- VIEWPORT = :viewport
106
- POINTER = :pointer
107
- ORIGINS = [VIEWPORT, POINTER].freeze
108
-
109
- def initialize(source, duration, x, y, element: nil, origin: nil)
110
- super(source)
111
- @duration = duration * 1000
112
- @x_offset = x
113
- @y_offset = y
114
- @origin = element || origin
115
- end
116
-
117
- def type
118
- :pointerMove
119
- end
120
-
121
- def encode
122
- output = {type: type, duration: @duration.to_i, x: @x_offset, y: @y_offset}
123
- output[:origin] = @origin
124
- output
125
- end
126
- end # Move
127
-
128
- class PointerCancel < Interaction
129
- def type
130
- :pointerCancel
131
- end
132
-
133
- def encode
134
- {type: type}
135
- end
136
- end # Cancel
137
68
  end # Interactions
138
69
  end # WebDriver
139
70
  end # Selenium
@@ -0,0 +1,60 @@
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 Interactions
23
+ #
24
+ # Action related to moving the pointer.
25
+ #
26
+ # @api private
27
+ #
28
+
29
+ class PointerMove < Interaction
30
+ include PointerEventProperties
31
+
32
+ VIEWPORT = :viewport
33
+ POINTER = :pointer
34
+ ORIGINS = [VIEWPORT, POINTER].freeze
35
+
36
+ def initialize(source, duration, x, y, **opts)
37
+ super(source)
38
+ @duration = duration * 1000
39
+ @x_offset = x
40
+ @y_offset = y
41
+ @origin = opts.delete(:element) || opts.delete(:origin) || :viewport
42
+ @type = :pointerMove
43
+ @opts = opts
44
+ end
45
+
46
+ def assert_source(source)
47
+ raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? PointerInput
48
+ end
49
+
50
+ def encode
51
+ process_opts.merge('type' => type.to_s,
52
+ 'duration' => @duration.to_i,
53
+ 'x' => @x_offset,
54
+ 'y' => @y_offset,
55
+ 'origin' => @origin)
56
+ end
57
+ end # PointerMove
58
+ end # Interactions
59
+ end # WebDriver
60
+ end # Selenium