selenium-webdriver 4.1.0 → 4.4.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.
- checksums.yaml +4 -4
- data/CHANGES +85 -1
- data/LICENSE +1 -1
- data/NOTICE +1 -1
- data/lib/selenium/server.rb +15 -10
- data/lib/selenium/webdriver/bidi/session.rb +38 -0
- data/lib/selenium/webdriver/bidi.rb +55 -0
- data/lib/selenium/webdriver/chrome/features.rb +5 -0
- data/lib/selenium/webdriver/chrome/options.rb +33 -19
- data/lib/selenium/webdriver/chrome.rb +0 -14
- data/lib/selenium/webdriver/common/action_builder.rb +108 -21
- data/lib/selenium/webdriver/common/driver.rb +22 -55
- data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +12 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -67
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -1
- data/lib/selenium/webdriver/common/element.rb +1 -1
- data/lib/selenium/webdriver/common/error.rb +1 -1
- data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
- data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
- data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
- data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
- data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
- data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
- data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
- data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
- data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
- data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
- data/lib/selenium/webdriver/common/interactions/scroll.rb +57 -0
- data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
- data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
- data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
- data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
- data/lib/selenium/webdriver/common/keys.rb +1 -0
- data/lib/selenium/webdriver/common/manager.rb +0 -27
- data/lib/selenium/webdriver/common/options.rb +2 -9
- data/lib/selenium/webdriver/common/platform.rb +4 -4
- data/lib/selenium/webdriver/common/search_context.rb +0 -6
- data/lib/selenium/webdriver/common/service_manager.rb +2 -3
- data/lib/selenium/webdriver/common/shadow_root.rb +1 -1
- data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
- data/lib/selenium/webdriver/common/takes_screenshot.rb +1 -1
- data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +83 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +73 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
- data/lib/selenium/webdriver/common/websocket_connection.rb +156 -0
- data/lib/selenium/webdriver/common/window.rb +6 -6
- data/lib/selenium/webdriver/common/zipper.rb +1 -1
- data/lib/selenium/webdriver/common.rb +17 -3
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +176 -0
- data/lib/selenium/webdriver/devtools/request.rb +1 -1
- data/lib/selenium/webdriver/devtools/response.rb +1 -1
- data/lib/selenium/webdriver/devtools.rb +6 -112
- data/lib/selenium/webdriver/edge/features.rb +1 -0
- data/lib/selenium/webdriver/firefox/driver.rb +1 -0
- data/lib/selenium/webdriver/firefox/features.rb +2 -5
- data/lib/selenium/webdriver/firefox/options.rb +3 -1
- data/lib/selenium/webdriver/firefox/profile.rb +1 -5
- data/lib/selenium/webdriver/firefox/util.rb +46 -0
- data/lib/selenium/webdriver/firefox.rb +1 -14
- data/lib/selenium/webdriver/ie.rb +0 -14
- data/lib/selenium/webdriver/remote/bridge.rb +54 -19
- data/lib/selenium/webdriver/remote/commands.rb +15 -6
- data/lib/selenium/webdriver/remote/driver.rb +0 -1
- data/lib/selenium/webdriver/remote/http/default.rb +6 -12
- data/lib/selenium/webdriver/remote/response.rb +2 -2
- data/lib/selenium/webdriver/safari.rb +0 -14
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +4 -4
- data/lib/selenium/webdriver/support/color.rb +7 -7
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -1
- data/lib/selenium/webdriver/support/guards.rb +1 -1
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +1 -0
- data/selenium-webdriver.gemspec +9 -6
- metadata +64 -12
- data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
|
@@ -23,11 +23,12 @@ module Selenium
|
|
|
23
23
|
attr_writer :default_move_duration
|
|
24
24
|
|
|
25
25
|
#
|
|
26
|
-
#
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
71
|
-
#
|
|
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
|
-
#
|
|
75
|
-
#
|
|
74
|
+
# The element is not scrolled into view.
|
|
75
|
+
# MoveTargetOutOfBoundsError will be raised if element with offset is outside the viewport
|
|
76
76
|
#
|
|
77
|
-
#
|
|
77
|
+
# When using offsets, both coordinates need to be passed.
|
|
78
78
|
#
|
|
79
|
-
# @example
|
|
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,60 @@ 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
|
|
91
|
-
# coordinates to the left of the
|
|
92
|
-
# @param [Integer] down_by Optional offset from the
|
|
93
|
-
# coordinates
|
|
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.
|
|
94
94
|
# @param [Symbol || String] device optional name of the PointerInput device to move.
|
|
95
95
|
# @return [ActionBuilder] A self reference.
|
|
96
96
|
#
|
|
97
97
|
|
|
98
|
-
def move_to(element, right_by = nil, down_by = nil, device: nil)
|
|
99
|
-
pointer =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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)
|
|
98
|
+
def move_to(element, right_by = nil, down_by = nil, device: nil, duration: default_move_duration, **opts)
|
|
99
|
+
pointer = pointer_input(device)
|
|
100
|
+
pointer.create_pointer_move(duration: duration,
|
|
101
|
+
x: right_by || 0,
|
|
102
|
+
y: down_by || 0,
|
|
103
|
+
origin: element,
|
|
104
|
+
**opts)
|
|
115
105
|
tick(pointer)
|
|
116
106
|
self
|
|
117
107
|
end
|
|
118
108
|
|
|
119
109
|
#
|
|
120
|
-
# Moves the
|
|
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.
|
|
110
|
+
# Moves the pointer from its current position by the given offset.
|
|
124
111
|
#
|
|
125
|
-
#
|
|
112
|
+
# The viewport is not scrolled if the coordinates provided are outside the viewport.
|
|
113
|
+
# MoveTargetOutOfBoundsError will be raised if the offsets are outside the viewport
|
|
114
|
+
#
|
|
115
|
+
# @example Move the pointer to a certain offset from its current position
|
|
126
116
|
#
|
|
127
117
|
# driver.action.move_by(100, 100).perform
|
|
128
118
|
#
|
|
129
|
-
# @param [Integer] right_by horizontal offset. A negative value means moving the
|
|
130
|
-
# @param [Integer] down_by vertical offset. A negative value means moving the
|
|
119
|
+
# @param [Integer] right_by horizontal offset. A negative value means moving the pointer left.
|
|
120
|
+
# @param [Integer] down_by vertical offset. A negative value means moving the pointer up.
|
|
131
121
|
# @param [Symbol || String] device optional name of the PointerInput device to move
|
|
132
122
|
# @return [ActionBuilder] A self reference.
|
|
133
123
|
# @raise [MoveTargetOutOfBoundsError] if the provided offset is outside the document's boundaries.
|
|
134
124
|
#
|
|
135
125
|
|
|
136
|
-
def move_by(right_by, down_by, device: nil)
|
|
137
|
-
pointer =
|
|
138
|
-
pointer.create_pointer_move(duration:
|
|
126
|
+
def move_by(right_by, down_by, device: nil, duration: default_move_duration, **opts)
|
|
127
|
+
pointer = pointer_input(device)
|
|
128
|
+
pointer.create_pointer_move(duration: duration,
|
|
139
129
|
x: Integer(right_by),
|
|
140
130
|
y: Integer(down_by),
|
|
141
|
-
origin: Interactions::PointerMove::POINTER
|
|
131
|
+
origin: Interactions::PointerMove::POINTER,
|
|
132
|
+
**opts)
|
|
142
133
|
tick(pointer)
|
|
143
134
|
self
|
|
144
135
|
end
|
|
145
136
|
|
|
146
137
|
#
|
|
147
|
-
# Moves the
|
|
148
|
-
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
138
|
+
# Moves the pointer to a given location in the viewport.
|
|
139
|
+
#
|
|
140
|
+
# The viewport is not scrolled if the coordinates provided are outside the viewport.
|
|
141
|
+
# MoveTargetOutOfBoundsError will be raised if the offsets are outside the viewport
|
|
151
142
|
#
|
|
152
|
-
# @example Move the
|
|
143
|
+
# @example Move the pointer to a certain position in the viewport
|
|
153
144
|
#
|
|
154
145
|
# driver.action.move_to_location(100, 100).perform
|
|
155
146
|
#
|
|
@@ -160,12 +151,13 @@ module Selenium
|
|
|
160
151
|
# @raise [MoveTargetOutOfBoundsError] if the provided x or y value is outside the document's boundaries.
|
|
161
152
|
#
|
|
162
153
|
|
|
163
|
-
def move_to_location(x, y, device: nil)
|
|
164
|
-
pointer =
|
|
165
|
-
pointer.create_pointer_move(duration:
|
|
154
|
+
def move_to_location(x, y, device: nil, duration: default_move_duration, **opts)
|
|
155
|
+
pointer = pointer_input(device)
|
|
156
|
+
pointer.create_pointer_move(duration: duration,
|
|
166
157
|
x: Integer(x),
|
|
167
158
|
y: Integer(y),
|
|
168
|
-
origin: Interactions::PointerMove::VIEWPORT
|
|
159
|
+
origin: Interactions::PointerMove::VIEWPORT,
|
|
160
|
+
**opts)
|
|
169
161
|
tick(pointer)
|
|
170
162
|
self
|
|
171
163
|
end
|
|
@@ -186,9 +178,9 @@ module Selenium
|
|
|
186
178
|
# @return [ActionBuilder] A self reference.
|
|
187
179
|
#
|
|
188
180
|
|
|
189
|
-
def click_and_hold(element = nil, device: nil)
|
|
181
|
+
def click_and_hold(element = nil, button: nil, device: nil)
|
|
190
182
|
move_to(element, device: device) if element
|
|
191
|
-
pointer_down(:left, device: device)
|
|
183
|
+
pointer_down(button || :left, device: device)
|
|
192
184
|
self
|
|
193
185
|
end
|
|
194
186
|
|
|
@@ -205,8 +197,8 @@ module Selenium
|
|
|
205
197
|
# @return [ActionBuilder] A self reference.
|
|
206
198
|
#
|
|
207
199
|
|
|
208
|
-
def release(device: nil)
|
|
209
|
-
pointer_up(:left, device: device)
|
|
200
|
+
def release(button: nil, device: nil)
|
|
201
|
+
pointer_up(button || :left, device: device)
|
|
210
202
|
self
|
|
211
203
|
end
|
|
212
204
|
|
|
@@ -232,10 +224,10 @@ module Selenium
|
|
|
232
224
|
# @return [ActionBuilder] A self reference.
|
|
233
225
|
#
|
|
234
226
|
|
|
235
|
-
def click(element = nil, device: nil)
|
|
227
|
+
def click(element = nil, button: nil, device: nil)
|
|
236
228
|
move_to(element, device: device) if element
|
|
237
|
-
pointer_down(:left, device: device)
|
|
238
|
-
pointer_up(:left, device: device)
|
|
229
|
+
pointer_down(button || :left, device: device)
|
|
230
|
+
pointer_up(button || :left, device: device)
|
|
239
231
|
self
|
|
240
232
|
end
|
|
241
233
|
|
|
@@ -290,10 +282,7 @@ module Selenium
|
|
|
290
282
|
#
|
|
291
283
|
|
|
292
284
|
def context_click(element = nil, device: nil)
|
|
293
|
-
|
|
294
|
-
pointer_down(:right, device: device)
|
|
295
|
-
pointer_up(:right, device: device)
|
|
296
|
-
self
|
|
285
|
+
click(element, button: :right, device: device)
|
|
297
286
|
end
|
|
298
287
|
|
|
299
288
|
#
|
|
@@ -348,15 +337,15 @@ module Selenium
|
|
|
348
337
|
|
|
349
338
|
private
|
|
350
339
|
|
|
351
|
-
def button_action(button, action
|
|
352
|
-
pointer =
|
|
353
|
-
pointer.send(action, button)
|
|
340
|
+
def button_action(button, action, device: nil, **opts)
|
|
341
|
+
pointer = pointer_input(device)
|
|
342
|
+
pointer.send(action, button, **opts)
|
|
354
343
|
tick(pointer)
|
|
355
344
|
self
|
|
356
345
|
end
|
|
357
346
|
|
|
358
|
-
def
|
|
359
|
-
|
|
347
|
+
def pointer_input(name = nil)
|
|
348
|
+
device(name: name, type: Interactions::POINTER) || add_pointer_input(:mouse, 'mouse')
|
|
360
349
|
end
|
|
361
350
|
end # PointerActions
|
|
362
351
|
end # WebDriver
|
|
@@ -0,0 +1,45 @@
|
|
|
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 cancel any other Pointer Action.
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
class PointerCancel < Interaction
|
|
30
|
+
def initialize(source)
|
|
31
|
+
super(source)
|
|
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
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def encode
|
|
40
|
+
{type: type}
|
|
41
|
+
end
|
|
42
|
+
end # PointerCancel
|
|
43
|
+
end # Interactions
|
|
44
|
+
end # WebDriver
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
def type
|
|
34
|
-
Interactions::POINTER
|
|
37
|
+
@type = Interactions::POINTER
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def encode
|
|
38
|
-
|
|
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,
|
|
52
|
-
add_action(PointerMove.new(self, duration, x, y,
|
|
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, element: nil, origin: nil, **opts)
|
|
37
|
+
super(source)
|
|
38
|
+
@duration = duration * 1000
|
|
39
|
+
@x_offset = x
|
|
40
|
+
@y_offset = y
|
|
41
|
+
@origin = element || 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
|
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
# Actions related to clicking, tapping or pressing the pointer.
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
class PointerPress < Interaction
|
|
30
|
+
include PointerEventProperties
|
|
31
|
+
|
|
32
|
+
BUTTONS = {left: 0,
|
|
33
|
+
touch: 0,
|
|
34
|
+
pen_contact: 0,
|
|
35
|
+
middle: 1,
|
|
36
|
+
right: 2,
|
|
37
|
+
pen_barrel: 2,
|
|
38
|
+
x1: 3,
|
|
39
|
+
back: 3,
|
|
40
|
+
x2: 4,
|
|
41
|
+
forward: 4}.freeze
|
|
42
|
+
DIRECTIONS = {down: :pointerDown, up: :pointerUp}.freeze
|
|
43
|
+
|
|
44
|
+
def initialize(source, direction, button, **opts)
|
|
45
|
+
super(source)
|
|
46
|
+
@direction = assert_direction(direction)
|
|
47
|
+
@button = assert_button(button)
|
|
48
|
+
@type = @direction
|
|
49
|
+
@opts = opts
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def encode
|
|
53
|
+
process_opts.merge('type' => type.to_s, 'button' => @button)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def assert_source(source)
|
|
59
|
+
raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? PointerInput
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def assert_button(button)
|
|
63
|
+
case button
|
|
64
|
+
when Symbol
|
|
65
|
+
raise ArgumentError, "#{button} is not a valid button!" unless BUTTONS.key? button
|
|
66
|
+
|
|
67
|
+
BUTTONS[button]
|
|
68
|
+
when Integer
|
|
69
|
+
raise ArgumentError, 'Button number cannot be negative!' if button.negative?
|
|
70
|
+
|
|
71
|
+
button
|
|
72
|
+
else
|
|
73
|
+
raise TypeError, "button must be a positive integer or one of #{BUTTONS.keys}, not #{button.class}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def assert_direction(direction)
|
|
78
|
+
raise ArgumentError, "#{direction.inspect} is not a valid button direction" unless DIRECTIONS.key? direction
|
|
79
|
+
|
|
80
|
+
DIRECTIONS[direction]
|
|
81
|
+
end
|
|
82
|
+
end # PointerPress
|
|
83
|
+
end # Interactions
|
|
84
|
+
end # WebDriver
|
|
85
|
+
end # Selenium
|
|
@@ -0,0 +1,57 @@
|
|
|
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 scrolling a wheel.
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
class Scroll < Interaction
|
|
30
|
+
def initialize(source:, x: 0, y: 0, delta_x: 0, delta_y: 0, origin: :viewport, duration: 0.25)
|
|
31
|
+
super(source)
|
|
32
|
+
@type = :scroll
|
|
33
|
+
@duration = duration * 1000
|
|
34
|
+
@origin = origin
|
|
35
|
+
@x_offset = x
|
|
36
|
+
@y_offset = y
|
|
37
|
+
@delta_x = delta_x
|
|
38
|
+
@delta_y = delta_y
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def assert_source(source)
|
|
42
|
+
raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? WheelInput
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def encode
|
|
46
|
+
{'type' => type.to_s,
|
|
47
|
+
'duration' => @duration.to_i,
|
|
48
|
+
'x' => @x_offset,
|
|
49
|
+
'y' => @y_offset,
|
|
50
|
+
'deltaX' => @delta_x,
|
|
51
|
+
'deltaY' => @delta_y,
|
|
52
|
+
'origin' => @origin.is_a?(Element) ? @origin : @origin.to_s}
|
|
53
|
+
end
|
|
54
|
+
end # PointerPress
|
|
55
|
+
end # Interactions
|
|
56
|
+
end # WebDriver
|
|
57
|
+
end # Selenium
|