selenium-webdriver 2.53.4 → 3.8.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 (152) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +363 -10
  3. data/LICENSE +1 -1
  4. data/README.md +2 -3
  5. data/lib/selenium-webdriver.rb +0 -2
  6. data/lib/selenium/server.rb +69 -70
  7. data/lib/selenium/webdriver.rb +32 -23
  8. data/lib/selenium/webdriver/atoms.rb +18 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +8 -0
  10. data/lib/selenium/webdriver/chrome.rb +8 -6
  11. data/lib/selenium/webdriver/chrome/driver.rb +112 -0
  12. data/lib/selenium/webdriver/chrome/options.rb +168 -0
  13. data/lib/selenium/webdriver/chrome/profile.rb +17 -17
  14. data/lib/selenium/webdriver/chrome/service.rb +22 -89
  15. data/lib/selenium/webdriver/common.rb +13 -6
  16. data/lib/selenium/webdriver/common/action_builder.rb +49 -57
  17. data/lib/selenium/webdriver/common/alert.rb +5 -15
  18. data/lib/selenium/webdriver/common/bridge_helper.rb +10 -17
  19. data/lib/selenium/webdriver/common/driver.rb +53 -68
  20. data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_addons.rb} +13 -23
  21. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -8
  22. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -7
  23. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -4
  24. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -4
  25. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +1 -5
  26. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -5
  27. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -9
  28. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +7 -7
  29. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -7
  30. data/lib/selenium/webdriver/common/element.rb +57 -39
  31. data/lib/selenium/webdriver/common/error.rb +204 -106
  32. data/lib/selenium/webdriver/common/file_reaper.rb +3 -11
  33. data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -10
  34. data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -10
  35. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +7 -18
  36. data/lib/selenium/webdriver/{safari/options.rb → common/interactions/input_device.rb} +20 -31
  37. data/lib/selenium/webdriver/common/interactions/interaction.rb +50 -0
  38. data/lib/selenium/webdriver/{safari/browser.rb → common/interactions/interactions.rb} +16 -15
  39. data/lib/selenium/webdriver/common/interactions/key_actions.rb +143 -0
  40. data/lib/selenium/webdriver/common/interactions/key_input.rb +62 -0
  41. data/lib/selenium/webdriver/{android.rb → common/interactions/none_input.rb} +11 -6
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +353 -0
  43. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +132 -0
  44. data/lib/selenium/webdriver/common/keyboard.rb +7 -14
  45. data/lib/selenium/webdriver/common/keys.rb +99 -82
  46. data/lib/selenium/webdriver/common/log_entry.rb +3 -6
  47. data/lib/selenium/webdriver/common/logger.rb +140 -0
  48. data/lib/selenium/webdriver/common/logs.rb +2 -6
  49. data/lib/selenium/webdriver/common/mouse.rb +9 -14
  50. data/lib/selenium/webdriver/common/navigation.rb +2 -6
  51. data/lib/selenium/webdriver/common/options.rb +20 -23
  52. data/lib/selenium/webdriver/common/platform.rb +70 -97
  53. data/lib/selenium/webdriver/common/port_prober.rb +3 -4
  54. data/lib/selenium/webdriver/common/profile_helper.rb +6 -11
  55. data/lib/selenium/webdriver/common/proxy.rb +58 -72
  56. data/lib/selenium/webdriver/common/search_context.rb +22 -29
  57. data/lib/selenium/webdriver/common/service.rb +161 -0
  58. data/lib/selenium/webdriver/common/socket_lock.rb +6 -14
  59. data/lib/selenium/webdriver/common/socket_poller.rb +5 -12
  60. data/lib/selenium/webdriver/common/target_locator.rb +11 -15
  61. data/lib/selenium/webdriver/common/timeouts.rb +4 -8
  62. data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -6
  63. data/lib/selenium/webdriver/common/touch_screen.rb +19 -23
  64. data/lib/selenium/webdriver/common/w3c_action_builder.rb +209 -0
  65. data/lib/selenium/webdriver/{phantomjs.rb → common/w3c_options.rb} +16 -14
  66. data/lib/selenium/webdriver/common/wait.rb +6 -13
  67. data/lib/selenium/webdriver/common/window.rb +48 -17
  68. data/lib/selenium/webdriver/common/zipper.rb +6 -10
  69. data/lib/selenium/webdriver/edge.rb +5 -12
  70. data/lib/selenium/webdriver/edge/bridge.rb +32 -63
  71. data/lib/selenium/webdriver/edge/driver.rb +73 -0
  72. data/lib/selenium/webdriver/edge/service.rb +18 -87
  73. data/lib/selenium/webdriver/firefox.rb +20 -11
  74. data/lib/selenium/webdriver/firefox/binary.rb +40 -56
  75. data/lib/selenium/webdriver/firefox/driver.rb +48 -0
  76. data/lib/selenium/webdriver/firefox/extension.rb +18 -8
  77. data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -11
  78. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  79. data/lib/selenium/webdriver/firefox/launcher.rb +13 -22
  80. data/lib/selenium/webdriver/firefox/legacy/driver.rb +79 -0
  81. data/lib/selenium/webdriver/{iphone.rb → firefox/marionette/bridge.rb} +25 -6
  82. data/lib/selenium/webdriver/firefox/marionette/driver.rb +96 -0
  83. data/lib/selenium/webdriver/firefox/options.rb +149 -0
  84. data/lib/selenium/webdriver/firefox/profile.rb +46 -46
  85. data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -18
  86. data/lib/selenium/webdriver/firefox/service.rb +23 -83
  87. data/lib/selenium/webdriver/firefox/util.rb +0 -4
  88. data/lib/selenium/webdriver/ie.rb +4 -8
  89. data/lib/selenium/webdriver/ie/driver.rb +90 -0
  90. data/lib/selenium/webdriver/ie/options.rb +136 -0
  91. data/lib/selenium/webdriver/ie/service.rb +58 -0
  92. data/lib/selenium/webdriver/remote.rb +8 -16
  93. data/lib/selenium/webdriver/remote/bridge.rb +96 -565
  94. data/lib/selenium/webdriver/remote/capabilities.rb +76 -94
  95. data/lib/selenium/webdriver/remote/driver.rb +49 -0
  96. data/lib/selenium/webdriver/remote/http/common.rb +22 -20
  97. data/lib/selenium/webdriver/remote/http/curb.rb +9 -12
  98. data/lib/selenium/webdriver/remote/http/default.rb +54 -41
  99. data/lib/selenium/webdriver/remote/http/persistent.rb +9 -8
  100. data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
  101. data/lib/selenium/webdriver/remote/oss/commands.rb +221 -0
  102. data/lib/selenium/webdriver/remote/response.rb +39 -27
  103. data/lib/selenium/webdriver/remote/server_error.rb +1 -5
  104. data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
  105. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +290 -0
  106. data/lib/selenium/webdriver/remote/w3c/commands.rb +148 -0
  107. data/lib/selenium/webdriver/safari.rb +20 -29
  108. data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +21 -30
  109. data/lib/selenium/webdriver/safari/service.rb +57 -0
  110. data/lib/selenium/webdriver/support.rb +1 -2
  111. data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -4
  112. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -5
  113. data/lib/selenium/webdriver/support/color.rb +57 -42
  114. data/lib/selenium/webdriver/support/escaper.rb +41 -0
  115. data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -40
  116. data/lib/selenium/webdriver/support/select.rb +33 -86
  117. data/selenium-webdriver.gemspec +22 -25
  118. metadata +254 -261
  119. data/lib/selenium-client.rb +0 -21
  120. data/lib/selenium/client.rb +0 -57
  121. data/lib/selenium/client/base.rb +0 -151
  122. data/lib/selenium/client/driver.rb +0 -29
  123. data/lib/selenium/client/errors.rb +0 -28
  124. data/lib/selenium/client/extensions.rb +0 -132
  125. data/lib/selenium/client/idiomatic.rb +0 -507
  126. data/lib/selenium/client/javascript_expression_builder.rb +0 -135
  127. data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
  128. data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
  129. data/lib/selenium/client/legacy_driver.rb +0 -1722
  130. data/lib/selenium/client/protocol.rb +0 -123
  131. data/lib/selenium/client/selenium_helper.rb +0 -49
  132. data/lib/selenium/rake/server_task.rb +0 -176
  133. data/lib/selenium/webdriver/android/bridge.rb +0 -68
  134. data/lib/selenium/webdriver/chrome/bridge.rb +0 -139
  135. data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
  136. data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
  137. data/lib/selenium/webdriver/common/html5/location.rb +0 -19
  138. data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
  139. data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
  140. data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
  141. data/lib/selenium/webdriver/ie/bridge.rb +0 -88
  142. data/lib/selenium/webdriver/ie/server.rb +0 -133
  143. data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
  144. data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
  145. data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
  146. data/lib/selenium/webdriver/remote/commands.rb +0 -211
  147. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
  148. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
  149. data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
  150. data/lib/selenium/webdriver/safari/bridge.rb +0 -135
  151. data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
  152. data/lib/selenium/webdriver/safari/server.rb +0 -187
@@ -0,0 +1,62 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Selenium
19
+ module WebDriver
20
+ module Interactions
21
+ class KeyInput < InputDevice
22
+ SUBTYPES = {down: :keyDown, up: :keyUp, pause: :pause}.freeze
23
+
24
+ def type
25
+ Interactions::KEY
26
+ end
27
+
28
+ def encode
29
+ return nil if no_actions?
30
+ {type: type, id: name, actions: @actions.map(&:encode)}
31
+ end
32
+
33
+ def create_key_down(key)
34
+ add_action(TypingInteraction.new(self, :down, key))
35
+ end
36
+
37
+ def create_key_up(key)
38
+ add_action(TypingInteraction.new(self, :up, key))
39
+ end
40
+
41
+ class TypingInteraction < Interaction
42
+ attr_reader :type
43
+
44
+ def initialize(source, type, key)
45
+ super(source)
46
+ @type = assert_type(type)
47
+ @key = Keys.encode_key(key)
48
+ end
49
+
50
+ def assert_type(type)
51
+ raise TypeError, "#{type.inspect} is not a valid key subtype" unless KeyInput::SUBTYPES.key? type
52
+ KeyInput::SUBTYPES[type]
53
+ end
54
+
55
+ def encode
56
+ {type: @type, value: @key}
57
+ end
58
+ end # TypingInteraction
59
+ end # KeyInput
60
+ end # Interactions
61
+ end # WebDriver
62
+ end # Selenium
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -19,10 +17,17 @@
19
17
 
20
18
  module Selenium
21
19
  module WebDriver
22
- module Android
20
+ module Interactions
21
+ class NoneInput < InputDevice
22
+ def type
23
+ Interactions::NONE
24
+ end
23
25
 
24
- end # Android
26
+ def encode
27
+ return nil if no_actions?
28
+ {type: type, id: name, actions: @actions.map(&:encode)}
29
+ end
30
+ end # NoneInput
31
+ end # Interactions
25
32
  end # WebDriver
26
33
  end # Selenium
27
-
28
- require 'selenium/webdriver/android/bridge'
@@ -0,0 +1,353 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Selenium
19
+ module WebDriver
20
+ module PointerActions
21
+ DEFAULT_MOVE_DURATION = 0.25 # 250 milliseconds
22
+
23
+ #
24
+ # Presses (without releasing) at the current location of the PointerInput device. This is equivalent to:
25
+ #
26
+ # driver.action.click_and_hold(nil)
27
+ #
28
+ # @example Clicking and holding at the current location
29
+ #
30
+ # driver.action.pointer_down(:left).perform
31
+ #
32
+ # @param [Selenium::WebDriver::Interactions::PointerPress::BUTTONS] button the button to press.
33
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
34
+ # that will be pressed
35
+ # @return [W3CActionBuilder] A self reference.
36
+ #
37
+
38
+ def pointer_down(button, device: nil)
39
+ button_action(button, action: :create_pointer_down, device: device)
40
+ end
41
+
42
+ #
43
+ # Releases the pressed mouse button at the current mouse location of the PointerInput device.
44
+ #
45
+ # @example Releasing a button after clicking and holding
46
+ #
47
+ # driver.action.pointer_down(:left).pointer_up(:left).perform
48
+ #
49
+ # @param [Selenium::WebDriver::Interactions::PointerPress::BUTTONS] button the button to release.
50
+ # @param [Symbol || String] device optional name of the PointerInput device with the button that will
51
+ # be released
52
+ # @return [W3CActionBuilder] A self reference.
53
+ #
54
+
55
+ def pointer_up(button, device: nil)
56
+ button_action(button, action: :create_pointer_up, device: device)
57
+ end
58
+
59
+ #
60
+ # Moves the mouse to the middle of the given element. The element is scrolled into
61
+ # view and its location is calculated using getBoundingClientRect. Then the
62
+ # mouse is moved to optional offset coordinates from the element.
63
+ #
64
+ # This is adapted to be backward compatible from non-W3C actions. W3C calculates offset from the center point
65
+ # of the element
66
+ #
67
+ # Note that when using offsets, both coordinates need to be passed.
68
+ #
69
+ # @example Scroll element into view and move the mouse to it
70
+ #
71
+ # el = driver.find_element(id: "some_id")
72
+ # driver.action.move_to(el).perform
73
+ #
74
+ # @example
75
+ #
76
+ # el = driver.find_element(id: "some_id")
77
+ # driver.action.move_to(el, 100, 100).perform
78
+ #
79
+ # @param [Selenium::WebDriver::Element] element to move to.
80
+ # @param [Integer] right_by Optional offset from the top-left corner. A negative value means
81
+ # coordinates to the left of the element.
82
+ # @param [Integer] down_by Optional offset from the top-left corner. A negative value means
83
+ # coordinates above the element.
84
+ # @param [Symbol || String] device optional name of the PointerInput device to move.
85
+ # @return [W3CActionBuilder] A self reference.
86
+ #
87
+
88
+ def move_to(element, right_by = nil, down_by = nil, device: nil)
89
+ pointer = get_pointer(device)
90
+ # New actions offset is from center of element
91
+ if right_by || down_by
92
+ size = element.size
93
+ left_offset = (size[:width] / 2).to_i
94
+ top_offset = (size[:height] / 2).to_i
95
+ left = -left_offset + (right_by || 0)
96
+ top = -top_offset + (down_by || 0)
97
+ else
98
+ left = 0
99
+ top = 0
100
+ end
101
+ pointer.create_pointer_move(duration: DEFAULT_MOVE_DURATION,
102
+ x: left,
103
+ y: top,
104
+ element: element)
105
+ tick(pointer)
106
+ self
107
+ end
108
+
109
+ #
110
+ # Moves the mouse from its current position by the given offset.
111
+ # If the coordinates provided are outside the viewport (the mouse will
112
+ # end up outside the browser window) then the viewport is scrolled to
113
+ # match.
114
+ #
115
+ # @example Move the mouse to a certain offset from its current position
116
+ #
117
+ # driver.action.move_by(100, 100).perform
118
+ #
119
+ # @param [Integer] right_by horizontal offset. A negative value means moving the mouse left.
120
+ # @param [Integer] down_by vertical offset. A negative value means moving the mouse up.
121
+ # @param [Symbol || String] device optional name of the PointerInput device to move
122
+ # @return [W3CActionBuilder] A self reference.
123
+ # @raise [MoveTargetOutOfBoundsError] if the provided offset is outside the document's boundaries.
124
+ #
125
+
126
+ def move_by(right_by, down_by, device: nil)
127
+ pointer = get_pointer(device)
128
+ pointer.create_pointer_move(duration: DEFAULT_MOVE_DURATION,
129
+ x: Integer(right_by),
130
+ y: Integer(down_by),
131
+ origin: Interactions::PointerMove::POINTER)
132
+ tick(pointer)
133
+ self
134
+ end
135
+
136
+ #
137
+ # Moves the mouse to a given location in the viewport.
138
+ # If the coordinates provided are outside the viewport (the mouse will
139
+ # end up outside the browser window) then the viewport is scrolled to
140
+ # match.
141
+ #
142
+ # @example Move the mouse to a certain position in the viewport
143
+ #
144
+ # driver.action.move_to_location(100, 100).perform
145
+ #
146
+ # @param [Integer] x horizontal position. Equivalent to a css 'left' value.
147
+ # @param [Integer] y vertical position. Equivalent to a css 'top' value.
148
+ # @param [Symbol || String] device optional name of the PointerInput device to move
149
+ # @return [W3CActionBuilder] A self reference.
150
+ # @raise [MoveTargetOutOfBoundsError] if the provided x or y value is outside the document's boundaries.
151
+ #
152
+
153
+ def move_to_location(x, y, device: nil)
154
+ pointer = get_pointer(device)
155
+ pointer.create_pointer_move(duration: DEFAULT_MOVE_DURATION,
156
+ x: Integer(x),
157
+ y: Integer(y),
158
+ origin: Interactions::PointerMove::VIEWPORT)
159
+ tick(pointer)
160
+ self
161
+ end
162
+
163
+ #
164
+ # Clicks (without releasing) in the middle of the given element. This is
165
+ # equivalent to:
166
+ #
167
+ # driver.action.move_to(element).click_and_hold
168
+ #
169
+ # @example Clicking and holding on some element
170
+ #
171
+ # el = driver.find_element(id: "some_id")
172
+ # driver.action.click_and_hold(el).perform
173
+ #
174
+ # @param [Selenium::WebDriver::Element] element the element to move to and click.
175
+ # @param [Symbol || String] device optional name of the PointerInput device to click with
176
+ # @return [W3CActionBuilder] A self reference.
177
+ #
178
+
179
+ def click_and_hold(element = nil, device: nil)
180
+ move_to(element, device: device) if element
181
+ pointer_down(:left, device: device)
182
+ self
183
+ end
184
+
185
+ #
186
+ # Releases the depressed left mouse button at the current mouse location.
187
+ #
188
+ # @example Releasing an element after clicking and holding it
189
+ #
190
+ # el = driver.find_element(id: "some_id")
191
+ # driver.action.click_and_hold(el).release.perform
192
+ #
193
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
194
+ # that will be released
195
+ # @return [W3CActionBuilder] A self reference.
196
+ #
197
+
198
+ def release(device: nil)
199
+ pointer_up(:left, device: device)
200
+ self
201
+ end
202
+
203
+ #
204
+ # Clicks in the middle of the given element. Equivalent to:
205
+ #
206
+ # driver.action.move_to(element).click
207
+ #
208
+ # When no element is passed, the current mouse position will be clicked.
209
+ #
210
+ # @example Clicking on an element
211
+ #
212
+ # el = driver.find_element(id: "some_id")
213
+ # driver.action.click(el).perform
214
+ #
215
+ # @example Clicking at the current mouse position
216
+ #
217
+ # driver.action.click.perform
218
+ #
219
+ # @param [Selenium::WebDriver::Element] element An optional element to click.
220
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
221
+ # that will be clicked
222
+ # @return [W3CActionBuilder] A self reference.
223
+ #
224
+
225
+ def click(element = nil, device: nil)
226
+ move_to(element, device: device) if element
227
+ pointer_down(:left, device: device)
228
+ pointer_up(:left, device: device)
229
+ self
230
+ end
231
+
232
+ #
233
+ # Performs a double-click at middle of the given element. Equivalent to:
234
+ #
235
+ # driver.action.move_to(element).double_click
236
+ #
237
+ # When no element is passed, the current mouse position will be double-clicked.
238
+ #
239
+ # @example Double-click an element
240
+ #
241
+ # el = driver.find_element(id: "some_id")
242
+ # driver.action.double_click(el).perform
243
+ #
244
+ # @example Double-clicking at the current mouse position
245
+ #
246
+ # driver.action.double_click.perform
247
+ #
248
+ # @param [Selenium::WebDriver::Element] element An optional element to move to.
249
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
250
+ # that will be double-clicked
251
+ # @return [W3CActionBuilder] A self reference.
252
+ #
253
+
254
+ def double_click(element = nil, device: nil)
255
+ move_to(element, device: device) if element
256
+ click(device: device)
257
+ click(device: device)
258
+ self
259
+ end
260
+
261
+ #
262
+ # Performs a context-click at middle of the given element. First performs
263
+ # a move_to to the location of the element.
264
+ #
265
+ # When no element is passed, the current mouse position will be context-clicked.
266
+ #
267
+ # @example Context-click at middle of given element
268
+ #
269
+ # el = driver.find_element(id: "some_id")
270
+ # driver.action.context_click(el).perform
271
+ #
272
+ # @example Context-clicking at the current mouse position
273
+ #
274
+ # driver.action.context_click.perform
275
+ #
276
+ # @param [Selenium::WebDriver::Element] element An element to context click.
277
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
278
+ # that will be context-clicked
279
+ # @return [W3CActionBuilder] A self reference.
280
+ #
281
+
282
+ def context_click(element = nil, device: nil)
283
+ move_to(element, device: device) if element
284
+ pointer_down(:right, device: device)
285
+ pointer_up(:right, device: device)
286
+ self
287
+ end
288
+
289
+ #
290
+ # A convenience method that performs click-and-hold at the location of the
291
+ # source element, moves to the location of the target element, then
292
+ # releases the mouse.
293
+ #
294
+ # @example Drag and drop one element onto another
295
+ #
296
+ # el1 = driver.find_element(id: "some_id1")
297
+ # el2 = driver.find_element(id: "some_id2")
298
+ # driver.action.drag_and_drop(el1, el2).perform
299
+ #
300
+ # @param [Selenium::WebDriver::Element] source element to emulate button down at.
301
+ # @param [Selenium::WebDriver::Element] target element to move to and release the
302
+ # mouse at.
303
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
304
+ # that will perform the drag and drop
305
+ # @return [W3CActionBuilder] A self reference.
306
+ #
307
+
308
+ def drag_and_drop(source, target, device: nil)
309
+ click_and_hold(source, device: device)
310
+ move_to(target, device: device)
311
+ release(device: device)
312
+ self
313
+ end
314
+
315
+ #
316
+ # A convenience method that performs click-and-hold at the location of
317
+ # the source element, moves by a given offset, then releases the mouse.
318
+ #
319
+ # @example Drag and drop an element by offset
320
+ #
321
+ # el = driver.find_element(id: "some_id1")
322
+ # driver.action.drag_and_drop_by(el, 100, 100).perform
323
+ #
324
+ # @param [Selenium::WebDriver::Element] source Element to emulate button down at.
325
+ # @param [Integer] right_by horizontal move offset.
326
+ # @param [Integer] down_by vertical move offset.
327
+ # @param [Symbol || String] device optional name of the PointerInput device with the button
328
+ # that will perform the drag and drop
329
+ # @return [W3CActionBuilder] A self reference.
330
+ #
331
+
332
+ def drag_and_drop_by(source, right_by, down_by, device: nil)
333
+ click_and_hold(source, device: device)
334
+ move_by(right_by, down_by, device: device)
335
+ release(device: device)
336
+ self
337
+ end
338
+
339
+ private
340
+
341
+ def button_action(button, action: nil, device: nil)
342
+ pointer = get_pointer(device)
343
+ pointer.send(action, button)
344
+ tick(pointer)
345
+ self
346
+ end
347
+
348
+ def get_pointer(device = nil)
349
+ get_device(device) || pointer_inputs.first
350
+ end
351
+ end # PointerActions
352
+ end # WebDriver
353
+ end # Selenium
@@ -0,0 +1,132 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Selenium
19
+ module WebDriver
20
+ module Interactions
21
+ class PointerInput < InputDevice
22
+ KIND = {mouse: :mouse, pen: :pen, touch: :touch}.freeze
23
+
24
+ attr_reader :kind
25
+
26
+ def initialize(kind, name: nil)
27
+ super(name)
28
+ @kind = assert_kind(kind)
29
+ end
30
+
31
+ def type
32
+ Interactions::POINTER
33
+ end
34
+
35
+ def encode
36
+ return nil if no_actions?
37
+ output = {type: type, id: name, actions: @actions.map(&:encode)}
38
+ output[:parameters] = {pointerType: kind}
39
+ output
40
+ end
41
+
42
+ def assert_kind(pointer)
43
+ raise TypeError, "#{pointer.inspect} is not a valid pointer type" unless KIND.key? pointer
44
+ KIND[pointer]
45
+ end
46
+
47
+ def create_pointer_move(duration: 0, x: 0, y: 0, element: nil, origin: nil)
48
+ add_action(PointerMove.new(self, duration, x, y, element: element, origin: origin))
49
+ end
50
+
51
+ def create_pointer_down(button)
52
+ add_action(PointerPress.new(self, :down, button))
53
+ end
54
+
55
+ def create_pointer_up(button)
56
+ add_action(PointerPress.new(self, :up, button))
57
+ end
58
+
59
+ def create_pointer_cancel
60
+ add_action(PointerCancel.new(self))
61
+ end
62
+ end # PointerInput
63
+
64
+ class PointerPress < Interaction
65
+ BUTTONS = {left: 0, middle: 1, right: 2}.freeze
66
+ DIRECTIONS = {down: :pointerDown, up: :pointerUp}.freeze
67
+
68
+ def initialize(source, direction, button)
69
+ super(source)
70
+ @direction = assert_direction(direction)
71
+ @button = assert_button(button)
72
+ end
73
+
74
+ def type
75
+ @direction
76
+ end
77
+
78
+ def assert_button(button)
79
+ if button.is_a? Symbol
80
+ raise TypeError, "#{button.inspect} is not a valid button!" unless BUTTONS.key? button
81
+ button = BUTTONS[button]
82
+ end
83
+ raise ArgumentError, 'Button number cannot be negative!' unless button >= 0
84
+ button
85
+ end
86
+
87
+ def assert_direction(direction)
88
+ raise TypeError, "#{direction.inspect} is not a valid button direction" unless DIRECTIONS.key? direction
89
+ DIRECTIONS[direction]
90
+ end
91
+
92
+ def encode
93
+ {type: type, button: @button}
94
+ end
95
+ end # PointerPress
96
+
97
+ class PointerMove < Interaction
98
+ VIEWPORT = :viewport
99
+ POINTER = :pointer
100
+ ORIGINS = [VIEWPORT, POINTER].freeze
101
+
102
+ def initialize(source, duration, x, y, element: nil, origin: nil)
103
+ super(source)
104
+ @duration = duration * 1000
105
+ @x_offset = x
106
+ @y_offset = y
107
+ @origin = element || origin
108
+ end
109
+
110
+ def type
111
+ :pointerMove
112
+ end
113
+
114
+ def encode
115
+ output = {type: type, duration: @duration.to_i, x: @x_offset, y: @y_offset}
116
+ output[:origin] = @origin
117
+ output
118
+ end
119
+ end # Move
120
+
121
+ class PointerCancel < Interaction
122
+ def type
123
+ :pointerCancel
124
+ end
125
+
126
+ def encode
127
+ {type: type}
128
+ end
129
+ end # Cancel
130
+ end # Interactions
131
+ end # WebDriver
132
+ end # Selenium