selenium-webdriver 3.142.7 → 4.0.3
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 +5 -5
- data/CHANGES +350 -5
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/NOTICE +2 -0
- data/README.md +4 -5
- data/lib/selenium/server.rb +69 -63
- data/lib/selenium/webdriver/atoms/findElements.js +122 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
- data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
- data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
- data/lib/selenium/webdriver/chrome/driver.rb +26 -83
- data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +50 -12
- data/lib/selenium/webdriver/chrome/options.rb +129 -58
- data/lib/selenium/webdriver/chrome/profile.rb +6 -3
- data/lib/selenium/webdriver/chrome/service.rb +8 -15
- data/lib/selenium/webdriver/chrome.rb +10 -9
- data/lib/selenium/webdriver/common/action_builder.rb +97 -249
- data/lib/selenium/webdriver/common/driver.rb +112 -23
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_cdp.rb} +10 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
- data/lib/selenium/webdriver/{firefox/util.rb → common/driver_extensions/has_devtools.rb} +16 -19
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
- data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
- data/lib/selenium/webdriver/common/element.rb +82 -22
- data/lib/selenium/webdriver/common/error.rb +32 -196
- data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
- data/lib/selenium/webdriver/common/log_entry.rb +2 -2
- data/lib/selenium/webdriver/common/logger.rb +50 -15
- data/lib/selenium/webdriver/common/manager.rb +15 -15
- data/lib/selenium/webdriver/common/options.rb +154 -23
- data/lib/selenium/webdriver/common/platform.rb +6 -1
- data/lib/selenium/webdriver/common/port_prober.rb +4 -6
- data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
- data/lib/selenium/webdriver/common/proxy.rb +6 -3
- data/lib/selenium/webdriver/common/search_context.rb +7 -3
- data/lib/selenium/webdriver/common/service.rb +17 -125
- data/lib/selenium/webdriver/common/service_manager.rb +151 -0
- data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
- data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
- data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
- data/lib/selenium/webdriver/common/target_locator.rb +32 -4
- data/lib/selenium/webdriver/common/timeouts.rb +31 -4
- data/lib/selenium/webdriver/common/wait.rb +1 -1
- data/lib/selenium/webdriver/common/window.rb +0 -4
- data/lib/selenium/webdriver/common/zipper.rb +1 -9
- data/lib/selenium/webdriver/common.rb +23 -17
- data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
- data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
- data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
- data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
- data/lib/selenium/webdriver/devtools/request.rb +67 -0
- data/lib/selenium/webdriver/devtools/response.rb +66 -0
- data/lib/selenium/webdriver/devtools.rb +182 -0
- data/lib/selenium/webdriver/edge/driver.rb +7 -29
- data/lib/selenium/webdriver/edge/features.rb +44 -0
- data/lib/selenium/webdriver/edge/options.rb +11 -48
- data/lib/selenium/webdriver/{common/w3c_manager.rb → edge/profile.rb} +7 -19
- data/lib/selenium/webdriver/edge/service.rb +10 -26
- data/lib/selenium/webdriver/edge.rb +11 -14
- data/lib/selenium/webdriver/firefox/driver.rb +31 -19
- data/lib/selenium/webdriver/firefox/extension.rb +8 -0
- data/lib/selenium/webdriver/firefox/features.rb +66 -0
- data/lib/selenium/webdriver/firefox/options.rb +70 -49
- data/lib/selenium/webdriver/firefox/profile.rb +21 -71
- data/lib/selenium/webdriver/firefox/service.rb +5 -9
- data/lib/selenium/webdriver/firefox.rb +22 -20
- data/lib/selenium/webdriver/ie/driver.rb +1 -47
- data/lib/selenium/webdriver/ie/options.rb +13 -44
- data/lib/selenium/webdriver/ie/service.rb +13 -15
- data/lib/selenium/webdriver/ie.rb +8 -7
- data/lib/selenium/webdriver/remote/bridge.rb +558 -86
- data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
- data/lib/selenium/webdriver/remote/commands.rb +163 -0
- data/lib/selenium/webdriver/remote/driver.rb +22 -12
- data/lib/selenium/webdriver/remote/http/common.rb +0 -5
- data/lib/selenium/webdriver/remote/http/default.rb +17 -20
- data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
- data/lib/selenium/webdriver/remote/response.rb +16 -47
- data/lib/selenium/webdriver/remote.rb +15 -13
- data/lib/selenium/webdriver/safari/driver.rb +3 -31
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
- data/lib/selenium/webdriver/safari/options.rb +10 -29
- data/lib/selenium/webdriver/safari/service.rb +4 -8
- data/lib/selenium/webdriver/safari.rb +17 -9
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
- data/lib/selenium/webdriver/support/color.rb +2 -2
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
- data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
- data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
- data/lib/selenium/webdriver/support/guards.rb +95 -0
- data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
- data/lib/selenium/webdriver/support/select.rb +3 -3
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +12 -12
- data/selenium-webdriver.gemspec +28 -12
- metadata +128 -69
- data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
- data/lib/selenium/webdriver/common/keyboard.rb +0 -70
- data/lib/selenium/webdriver/common/mouse.rb +0 -89
- data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
- data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
- data/lib/selenium/webdriver/edge/bridge.rb +0 -76
- data/lib/selenium/webdriver/firefox/binary.rb +0 -187
- data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
- data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
- data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
- data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
- data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
- data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
|
@@ -19,346 +19,194 @@
|
|
|
19
19
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
|
-
#
|
|
23
|
-
# The ActionBuilder provides the user a way to set up and perform
|
|
24
|
-
# complex user interactions.
|
|
25
|
-
#
|
|
26
|
-
# This class should not be instantiated directly, but is created by Driver#action
|
|
27
|
-
#
|
|
28
|
-
# @example
|
|
29
|
-
#
|
|
30
|
-
# driver.action.key_down(:shift).
|
|
31
|
-
# click(element).
|
|
32
|
-
# click(second_element).
|
|
33
|
-
# key_up(:shift).
|
|
34
|
-
# drag_and_drop(element, third_element).
|
|
35
|
-
# perform
|
|
36
|
-
#
|
|
37
|
-
|
|
38
22
|
class ActionBuilder
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
23
|
+
include KeyActions # Actions specific to key inputs
|
|
24
|
+
include PointerActions # Actions specific to pointer inputs
|
|
42
25
|
|
|
43
|
-
|
|
44
|
-
@devices = {
|
|
45
|
-
mouse: mouse,
|
|
46
|
-
keyboard: keyboard
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@actions = []
|
|
50
|
-
end
|
|
26
|
+
attr_reader :devices
|
|
51
27
|
|
|
52
28
|
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
29
|
+
# Initialize a W3C Action Builder. Differs from previous by requiring a bridge and allowing asynchronous actions.
|
|
30
|
+
# The W3C implementation allows asynchronous actions per device. e.g. A key can be pressed at the same time that
|
|
31
|
+
# the mouse is moving. Keep in mind that pauses must be added for other devices in order to line up the actions
|
|
32
|
+
# correctly when using asynchronous.
|
|
57
33
|
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
# @
|
|
64
|
-
#
|
|
65
|
-
# driver.action.key_down(:control).perform
|
|
66
|
-
#
|
|
67
|
-
# @example Press a key on an element
|
|
68
|
-
#
|
|
69
|
-
# el = driver.find_element(id: "some_id")
|
|
70
|
-
# driver.action.key_down(el, :shift).perform
|
|
34
|
+
# @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance
|
|
35
|
+
# @param [Selenium::WebDriver::Interactions::PointerInput] mouse PointerInput for the mouse.
|
|
36
|
+
# @param [Selenium::WebDriver::Interactions::KeyInput] keyboard KeyInput for the keyboard.
|
|
37
|
+
# @param [Boolean] async Whether to perform the actions asynchronously per device. Defaults to false for
|
|
38
|
+
# backwards compatibility.
|
|
39
|
+
# @return [ActionBuilder] A self reference.
|
|
71
40
|
#
|
|
72
|
-
# @overload key_down(key)
|
|
73
|
-
# @param [:shift, :alt, :control, :command, :meta] key The modifier key to press
|
|
74
|
-
# @overload key_down(element, key)
|
|
75
|
-
# @param [Element] element An optional element to move to first
|
|
76
|
-
# @param [:shift, :alt, :control, :command, :meta] key The modifier key to press
|
|
77
|
-
# @raise [ArgumentError] if the given key is not a modifier
|
|
78
|
-
# @return [ActionBuilder] A self reference
|
|
79
41
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@
|
|
84
|
-
|
|
42
|
+
def initialize(bridge, mouse, keyboard, async = false)
|
|
43
|
+
# For backwards compatibility, automatically include mouse & keyboard
|
|
44
|
+
@bridge = bridge
|
|
45
|
+
@devices = [mouse, keyboard]
|
|
46
|
+
@async = async
|
|
85
47
|
end
|
|
86
48
|
|
|
87
49
|
#
|
|
88
|
-
#
|
|
89
|
-
# Releasing a non-depressed modifier key will yield undefined behaviour.
|
|
50
|
+
# Adds a PointerInput device of the given kind
|
|
90
51
|
#
|
|
91
|
-
# @example
|
|
52
|
+
# @example Add a touch pointer input device
|
|
92
53
|
#
|
|
93
|
-
#
|
|
54
|
+
# builder = device.action
|
|
55
|
+
# builder.add_pointer_input('touch', :touch)
|
|
94
56
|
#
|
|
95
|
-
# @
|
|
57
|
+
# @param [String] name name for the device
|
|
58
|
+
# @param [Symbol] kind kind of pointer device to create
|
|
59
|
+
# @return [Interactions::PointerInput] The pointer input added
|
|
96
60
|
#
|
|
97
|
-
# el = driver.find_element(id: "some_id")
|
|
98
|
-
# driver.action.key_up(el, :alt).perform
|
|
99
61
|
#
|
|
100
|
-
# @overload key_up(key)
|
|
101
|
-
# @param [:shift, :alt, :control, :command, :meta] key The modifier key to release
|
|
102
|
-
# @overload key_up(element, key)
|
|
103
|
-
# @param [Element] element An optional element to move to first
|
|
104
|
-
# @param [:shift, :alt, :control, :command, :meta] key The modifier key to release
|
|
105
|
-
# @raise [ArgumentError] if the given key is not a modifier
|
|
106
|
-
# @return [ActionBuilder] A self reference
|
|
107
|
-
#
|
|
108
|
-
|
|
109
|
-
def key_up(*args)
|
|
110
|
-
@actions << [:mouse, :click, [args.shift]] if args.first.is_a? Element
|
|
111
62
|
|
|
112
|
-
|
|
113
|
-
|
|
63
|
+
def add_pointer_input(kind, name)
|
|
64
|
+
new_input = Interactions.pointer(kind, name: name)
|
|
65
|
+
add_input(new_input)
|
|
66
|
+
new_input
|
|
114
67
|
end
|
|
115
68
|
|
|
116
69
|
#
|
|
117
|
-
#
|
|
118
|
-
# Element#send_keys(keys) on the active element in two ways:
|
|
119
|
-
#
|
|
120
|
-
# * The modifier keys included in this call are not released.
|
|
121
|
-
# * There is no attempt to re-focus the element - so send_keys(:tab) for switching elements should work.
|
|
122
|
-
#
|
|
123
|
-
# @example Send the text "help" to an element
|
|
124
|
-
#
|
|
125
|
-
# el = driver.find_element(id: "some_id")
|
|
126
|
-
# driver.action.send_keys(el, "help").perform
|
|
70
|
+
# Adds a KeyInput device
|
|
127
71
|
#
|
|
128
|
-
# @example
|
|
72
|
+
# @example Add a key input device
|
|
129
73
|
#
|
|
130
|
-
#
|
|
74
|
+
# builder = device.action
|
|
75
|
+
# builder.add_key_input('keyboard2')
|
|
131
76
|
#
|
|
132
|
-
# @
|
|
133
|
-
#
|
|
134
|
-
# @overload send_keys(element, keys)
|
|
135
|
-
# @param [Element] element An optional element to move to first
|
|
136
|
-
# @param [Array, Symbol, String] keys The key(s) to press and release
|
|
137
|
-
# @return [ActionBuilder] A self reference
|
|
77
|
+
# @param [String] name name for the device
|
|
78
|
+
# @return [Interactions::KeyInput] The key input added
|
|
138
79
|
#
|
|
139
80
|
|
|
140
|
-
def
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
self
|
|
81
|
+
def add_key_input(name)
|
|
82
|
+
new_input = Interactions.key(name)
|
|
83
|
+
add_input(new_input)
|
|
84
|
+
new_input
|
|
145
85
|
end
|
|
146
86
|
|
|
147
87
|
#
|
|
148
|
-
#
|
|
149
|
-
# equivalent to:
|
|
150
|
-
#
|
|
151
|
-
# driver.action.move_to(element).click_and_hold
|
|
152
|
-
#
|
|
153
|
-
# @example Clicking and holding on some element
|
|
88
|
+
# Retrieves the input device for the given name
|
|
154
89
|
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
# @param [Element] element the element to move to and click.
|
|
159
|
-
# @return [ActionBuilder] A self reference.
|
|
90
|
+
# @param [String] name name of the input device
|
|
91
|
+
# @return [Selenium::WebDriver::Interactions::InputDevice] input device with given name
|
|
160
92
|
#
|
|
161
93
|
|
|
162
|
-
def
|
|
163
|
-
@
|
|
164
|
-
self
|
|
94
|
+
def get_device(name)
|
|
95
|
+
@devices.find { |device| device.name == name.to_s }
|
|
165
96
|
end
|
|
166
97
|
|
|
167
98
|
#
|
|
168
|
-
#
|
|
99
|
+
# Retrieves the current PointerInput devices
|
|
169
100
|
#
|
|
170
|
-
# @
|
|
171
|
-
#
|
|
172
|
-
# el = driver.find_element(id: "some_id")
|
|
173
|
-
# driver.action.click_and_hold(el).release.perform
|
|
174
|
-
#
|
|
175
|
-
# @return [ActionBuilder] A self reference.
|
|
101
|
+
# @return [Array] array of current PointerInput devices
|
|
176
102
|
#
|
|
177
103
|
|
|
178
|
-
def
|
|
179
|
-
@
|
|
180
|
-
self
|
|
104
|
+
def pointer_inputs
|
|
105
|
+
@devices.select { |device| device.type == Interactions::POINTER }
|
|
181
106
|
end
|
|
182
107
|
|
|
183
108
|
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
# driver.action.move_to(element).click
|
|
187
|
-
#
|
|
188
|
-
# When no element is passed, the current mouse position will be clicked.
|
|
189
|
-
#
|
|
190
|
-
# @example Clicking on an element
|
|
109
|
+
# Retrieves the current KeyInput device
|
|
191
110
|
#
|
|
192
|
-
#
|
|
193
|
-
# driver.action.click(el).perform
|
|
194
|
-
#
|
|
195
|
-
# @example Clicking at the current mouse position
|
|
196
|
-
#
|
|
197
|
-
# driver.action.click.perform
|
|
198
|
-
#
|
|
199
|
-
# @param [Selenium::WebDriver::Element] element An optional element to click.
|
|
200
|
-
# @return [ActionBuilder] A self reference.
|
|
111
|
+
# @return [Selenium::WebDriver::Interactions::InputDevice] current KeyInput device
|
|
201
112
|
#
|
|
202
113
|
|
|
203
|
-
def
|
|
204
|
-
@
|
|
205
|
-
self
|
|
114
|
+
def key_inputs
|
|
115
|
+
@devices.select { |device| device.type == Interactions::KEY }
|
|
206
116
|
end
|
|
207
117
|
|
|
208
118
|
#
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
-
# driver.action.move_to(element).double_click
|
|
119
|
+
# Creates a pause for the given device of the given duration. If no duration is given, the pause will only wait
|
|
120
|
+
# for all actions to complete in that tick.
|
|
212
121
|
#
|
|
213
|
-
# @example
|
|
122
|
+
# @example Send keys to an element
|
|
214
123
|
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
124
|
+
# action_builder = driver.action
|
|
125
|
+
# keyboard = action_builder.key_input
|
|
126
|
+
# el = driver.find_element(id: "some_id")
|
|
127
|
+
# driver.action.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys').perform
|
|
217
128
|
#
|
|
218
|
-
# @param [
|
|
129
|
+
# @param [InputDevice] device Input device to pause
|
|
130
|
+
# @param [Float] duration Duration to pause
|
|
219
131
|
# @return [ActionBuilder] A self reference.
|
|
220
132
|
#
|
|
221
133
|
|
|
222
|
-
def
|
|
223
|
-
|
|
134
|
+
def pause(device, duration = nil)
|
|
135
|
+
device.create_pause(duration)
|
|
224
136
|
self
|
|
225
137
|
end
|
|
226
138
|
|
|
227
139
|
#
|
|
228
|
-
#
|
|
229
|
-
# view and its location is calculated using getBoundingClientRect. Then the
|
|
230
|
-
# mouse is moved to optional offset coordinates from the element.
|
|
231
|
-
#
|
|
232
|
-
# Note that when using offsets, both coordinates need to be passed.
|
|
233
|
-
#
|
|
234
|
-
# @example Scroll element into view and move the mouse to it
|
|
140
|
+
# Creates multiple pauses for the given device of the given duration.
|
|
235
141
|
#
|
|
236
|
-
#
|
|
237
|
-
# driver.action.move_to(el).perform
|
|
238
|
-
#
|
|
239
|
-
# @example
|
|
142
|
+
# @example Send keys to an element
|
|
240
143
|
#
|
|
144
|
+
# action_builder = driver.action
|
|
145
|
+
# keyboard = action_builder.key_input
|
|
241
146
|
# el = driver.find_element(id: "some_id")
|
|
242
|
-
# driver.action.
|
|
147
|
+
# driver.action.click(el).pauses(keyboard, 3).send_keys('keys').perform
|
|
243
148
|
#
|
|
244
|
-
# @param [
|
|
245
|
-
# @param [Integer]
|
|
246
|
-
#
|
|
247
|
-
# @param [Integer] down_by Optional offset from the top-left corner. A negative value means
|
|
248
|
-
# coordinates above the element.
|
|
149
|
+
# @param [InputDevice] device Input device to pause
|
|
150
|
+
# @param [Integer] number of pauses to add for the device
|
|
151
|
+
# @param [Float] duration Duration to pause
|
|
249
152
|
# @return [ActionBuilder] A self reference.
|
|
250
153
|
#
|
|
251
154
|
|
|
252
|
-
def
|
|
253
|
-
|
|
254
|
-
[:mouse, :move_to, [element, Integer(right_by), Integer(down_by)]]
|
|
255
|
-
else
|
|
256
|
-
[:mouse, :move_to, [element]]
|
|
257
|
-
end
|
|
258
|
-
|
|
155
|
+
def pauses(device, number, duration = nil)
|
|
156
|
+
number.times { device.create_pause(duration) }
|
|
259
157
|
self
|
|
260
158
|
end
|
|
261
159
|
|
|
262
160
|
#
|
|
263
|
-
#
|
|
264
|
-
# If the coordinates provided are outside the viewport (the mouse will
|
|
265
|
-
# end up outside the browser window) then the viewport is scrolled to
|
|
266
|
-
# match.
|
|
267
|
-
#
|
|
268
|
-
# @example Move the mouse to a certain offset from its current position
|
|
269
|
-
#
|
|
270
|
-
# driver.action.move_by(100, 100).perform
|
|
271
|
-
#
|
|
272
|
-
# @param [Integer] right_by horizontal offset. A negative value means moving the
|
|
273
|
-
# mouse left.
|
|
274
|
-
# @param [Integer] down_by vertical offset. A negative value means moving the mouse
|
|
275
|
-
# up.
|
|
276
|
-
# @return [ActionBuilder] A self reference.
|
|
277
|
-
# @raise [MoveTargetOutOfBoundsError] if the provided offset is outside
|
|
278
|
-
# the document's boundaries.
|
|
161
|
+
# Executes the actions added to the builder.
|
|
279
162
|
#
|
|
280
163
|
|
|
281
|
-
def
|
|
282
|
-
@
|
|
283
|
-
|
|
164
|
+
def perform
|
|
165
|
+
@bridge.send_actions @devices.map(&:encode).compact
|
|
166
|
+
clear_all_actions
|
|
167
|
+
nil
|
|
284
168
|
end
|
|
285
169
|
|
|
286
170
|
#
|
|
287
|
-
#
|
|
288
|
-
# a move_to to the location of the element.
|
|
289
|
-
#
|
|
290
|
-
# @example Context-click at middle of given element
|
|
291
|
-
#
|
|
292
|
-
# el = driver.find_element(id: "some_id")
|
|
293
|
-
# driver.action.context_click(el).perform
|
|
294
|
-
#
|
|
295
|
-
# @param [Selenium::WebDriver::Element] element An element to context click.
|
|
296
|
-
# @return [ActionBuilder] A self reference.
|
|
171
|
+
# Clears all actions from the builder.
|
|
297
172
|
#
|
|
298
173
|
|
|
299
|
-
def
|
|
300
|
-
@
|
|
301
|
-
self
|
|
174
|
+
def clear_all_actions
|
|
175
|
+
@devices.each(&:clear_actions)
|
|
302
176
|
end
|
|
303
177
|
|
|
304
178
|
#
|
|
305
|
-
#
|
|
306
|
-
# source element, moves to the location of the target element, then
|
|
307
|
-
# releases the mouse.
|
|
308
|
-
#
|
|
309
|
-
# @example Drag and drop one element onto another
|
|
310
|
-
#
|
|
311
|
-
# el1 = driver.find_element(id: "some_id1")
|
|
312
|
-
# el2 = driver.find_element(id: "some_id2")
|
|
313
|
-
# driver.action.drag_and_drop(el1, el2).perform
|
|
314
|
-
#
|
|
315
|
-
# @param [Selenium::WebDriver::Element] source element to emulate button down at.
|
|
316
|
-
# @param [Selenium::WebDriver::Element] target element to move to and release the
|
|
317
|
-
# mouse at.
|
|
318
|
-
# @return [ActionBuilder] A self reference.
|
|
179
|
+
# Releases all action states from the browser.
|
|
319
180
|
#
|
|
320
181
|
|
|
321
|
-
def
|
|
322
|
-
|
|
323
|
-
move_to target
|
|
324
|
-
release
|
|
325
|
-
|
|
326
|
-
self
|
|
182
|
+
def release_actions
|
|
183
|
+
@bridge.release_actions
|
|
327
184
|
end
|
|
328
185
|
|
|
186
|
+
private
|
|
187
|
+
|
|
329
188
|
#
|
|
330
|
-
#
|
|
331
|
-
# the source element, moves by a given offset, then releases the mouse.
|
|
332
|
-
#
|
|
333
|
-
# @example Drag and drop an element by offset
|
|
189
|
+
# Adds pauses for all devices but the given devices
|
|
334
190
|
#
|
|
335
|
-
#
|
|
336
|
-
# driver.action.drag_and_drop_by(el, 100, 100).perform
|
|
337
|
-
#
|
|
338
|
-
# @param [Selenium::WebDriver::Element] source Element to emulate button down at.
|
|
339
|
-
# @param [Integer] right_by horizontal move offset.
|
|
340
|
-
# @param [Integer] down_by vertical move offset.
|
|
341
|
-
# @return [ActionBuilder] A self reference.
|
|
191
|
+
# @param [Array[InputDevice]] action_devices Array of Input Devices performing an action in this tick.
|
|
342
192
|
#
|
|
343
193
|
|
|
344
|
-
def
|
|
345
|
-
|
|
346
|
-
move_by right_by, down_by
|
|
347
|
-
release
|
|
194
|
+
def tick(*action_devices)
|
|
195
|
+
return if @async
|
|
348
196
|
|
|
349
|
-
|
|
197
|
+
@devices.each { |device| device.create_pause unless action_devices.include? device }
|
|
350
198
|
end
|
|
351
199
|
|
|
352
200
|
#
|
|
353
|
-
#
|
|
201
|
+
# Adds an InputDevice
|
|
354
202
|
#
|
|
355
203
|
|
|
356
|
-
def
|
|
357
|
-
@
|
|
358
|
-
@devices.
|
|
204
|
+
def add_input(device)
|
|
205
|
+
unless @async
|
|
206
|
+
max_device = @devices.max { |a, b| a.actions.length <=> b.actions.length }
|
|
207
|
+
pauses(device, max_device.actions.length)
|
|
359
208
|
end
|
|
360
|
-
|
|
361
|
-
nil
|
|
209
|
+
@devices << device
|
|
362
210
|
end
|
|
363
211
|
end # ActionBuilder
|
|
364
212
|
end # WebDriver
|
|
@@ -30,6 +30,7 @@ module Selenium
|
|
|
30
30
|
|
|
31
31
|
class Driver
|
|
32
32
|
include SearchContext
|
|
33
|
+
include TakesScreenshot
|
|
33
34
|
|
|
34
35
|
class << self
|
|
35
36
|
#
|
|
@@ -43,19 +44,17 @@ module Selenium
|
|
|
43
44
|
def for(browser, opts = {})
|
|
44
45
|
case browser
|
|
45
46
|
when :chrome
|
|
46
|
-
Chrome::Driver.new(opts)
|
|
47
|
+
Chrome::Driver.new(**opts)
|
|
47
48
|
when :internet_explorer, :ie
|
|
48
|
-
IE::Driver.new(opts)
|
|
49
|
+
IE::Driver.new(**opts)
|
|
49
50
|
when :safari
|
|
50
|
-
Safari::Driver.new(opts)
|
|
51
|
-
when :phantomjs
|
|
52
|
-
PhantomJS::Driver.new(opts)
|
|
51
|
+
Safari::Driver.new(**opts)
|
|
53
52
|
when :firefox, :ff
|
|
54
|
-
Firefox::Driver.new(opts)
|
|
53
|
+
Firefox::Driver.new(**opts)
|
|
55
54
|
when :edge
|
|
56
|
-
Edge::Driver.new(opts)
|
|
55
|
+
Edge::Driver.new(**opts)
|
|
57
56
|
when :remote
|
|
58
|
-
Remote::Driver.new(opts)
|
|
57
|
+
Remote::Driver.new(**opts)
|
|
59
58
|
else
|
|
60
59
|
raise ArgumentError, "unknown driver: #{browser.inspect}"
|
|
61
60
|
end
|
|
@@ -69,13 +68,27 @@ module Selenium
|
|
|
69
68
|
# @api private
|
|
70
69
|
#
|
|
71
70
|
|
|
72
|
-
def initialize(bridge, listener: nil)
|
|
73
|
-
@
|
|
74
|
-
@
|
|
71
|
+
def initialize(bridge: nil, listener: nil, **opts)
|
|
72
|
+
@service = nil
|
|
73
|
+
@devtools = nil
|
|
74
|
+
bridge ||= create_bridge(**opts)
|
|
75
|
+
add_extensions(bridge.browser)
|
|
76
|
+
@bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
|
|
75
77
|
end
|
|
76
78
|
|
|
77
79
|
def inspect
|
|
78
|
-
format '#<%<class>s:0x%<hash>x browser=%<browser>s>', class: self.class, hash: hash * 2,
|
|
80
|
+
format '#<%<class>s:0x%<hash>x browser=%<browser>s>', class: self.class, hash: hash * 2,
|
|
81
|
+
browser: bridge.browser.inspect
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# information about whether a remote end is in a state in which it can create new sessions,
|
|
86
|
+
# and may include additional meta information.
|
|
87
|
+
#
|
|
88
|
+
# @return [Hash]
|
|
89
|
+
#
|
|
90
|
+
def status
|
|
91
|
+
@bridge.status
|
|
79
92
|
end
|
|
80
93
|
|
|
81
94
|
#
|
|
@@ -106,8 +119,8 @@ module Selenium
|
|
|
106
119
|
end
|
|
107
120
|
|
|
108
121
|
#
|
|
109
|
-
# @return [ActionBuilder
|
|
110
|
-
# @see ActionBuilder
|
|
122
|
+
# @return [ActionBuilder]
|
|
123
|
+
# @see ActionBuilder
|
|
111
124
|
#
|
|
112
125
|
|
|
113
126
|
def action
|
|
@@ -166,6 +179,9 @@ module Selenium
|
|
|
166
179
|
|
|
167
180
|
def quit
|
|
168
181
|
bridge.quit
|
|
182
|
+
ensure
|
|
183
|
+
@service&.stop
|
|
184
|
+
@devtools&.close
|
|
169
185
|
end
|
|
170
186
|
|
|
171
187
|
#
|
|
@@ -271,7 +287,7 @@ module Selenium
|
|
|
271
287
|
end
|
|
272
288
|
|
|
273
289
|
def browser
|
|
274
|
-
bridge
|
|
290
|
+
bridge&.browser
|
|
275
291
|
end
|
|
276
292
|
|
|
277
293
|
def capabilities
|
|
@@ -283,26 +299,99 @@ module Selenium
|
|
|
283
299
|
# @see SearchContext
|
|
284
300
|
#
|
|
285
301
|
|
|
286
|
-
def ref
|
|
302
|
+
def ref
|
|
303
|
+
[:driver, nil]
|
|
304
|
+
end
|
|
287
305
|
|
|
288
306
|
private
|
|
289
307
|
|
|
290
308
|
attr_reader :bridge
|
|
291
309
|
|
|
310
|
+
def create_bridge(**opts)
|
|
311
|
+
opts[:url] ||= service_url(opts)
|
|
312
|
+
caps = opts.delete(:capabilities)
|
|
313
|
+
# NOTE: This is deprecated
|
|
314
|
+
cap_array = caps.is_a?(Hash) ? [caps] : Array(caps)
|
|
315
|
+
|
|
316
|
+
desired_capabilities = opts.delete(:desired_capabilities)
|
|
317
|
+
if desired_capabilities
|
|
318
|
+
WebDriver.logger.deprecate(':desired_capabilities as a parameter for driver initialization',
|
|
319
|
+
':capabilities with an Array value of capabilities/options if necessary',
|
|
320
|
+
id: :desired_capabilities)
|
|
321
|
+
desired_capabilities = Remote::Capabilities.new(desired_capabilities) if desired_capabilities.is_a?(Hash)
|
|
322
|
+
cap_array << desired_capabilities
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
options = opts.delete(:options)
|
|
326
|
+
if options
|
|
327
|
+
WebDriver.logger.deprecate(':options as a parameter for driver initialization',
|
|
328
|
+
':capabilities with an Array of value capabilities/options if necessary',
|
|
329
|
+
id: :browser_options)
|
|
330
|
+
cap_array << options
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
capabilities = generate_capabilities(cap_array)
|
|
334
|
+
|
|
335
|
+
bridge_opts = {http_client: opts.delete(:http_client), url: opts.delete(:url)}
|
|
336
|
+
raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
|
337
|
+
|
|
338
|
+
bridge = Remote::Bridge.new(**bridge_opts)
|
|
339
|
+
|
|
340
|
+
bridge.create_session(capabilities)
|
|
341
|
+
bridge
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def generate_capabilities(cap_array)
|
|
345
|
+
cap_array.map { |cap|
|
|
346
|
+
if cap.is_a? Symbol
|
|
347
|
+
cap = Remote::Capabilities.send(cap)
|
|
348
|
+
elsif cap.is_a? Hash
|
|
349
|
+
new_message = 'Capabilities instance initialized with the Hash, or build values with Options class'
|
|
350
|
+
WebDriver.logger.deprecate("passing a Hash value to :capabilities",
|
|
351
|
+
new_message,
|
|
352
|
+
id: :capabilities_hash)
|
|
353
|
+
cap = Remote::Capabilities.new(cap)
|
|
354
|
+
elsif !cap.respond_to? :as_json
|
|
355
|
+
msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
|
|
356
|
+
raise ArgumentError, msg
|
|
357
|
+
end
|
|
358
|
+
cap&.as_json
|
|
359
|
+
}.inject(:merge) || Remote::Capabilities.send(browser || :new)
|
|
360
|
+
end
|
|
361
|
+
|
|
292
362
|
def service_url(opts)
|
|
293
|
-
|
|
363
|
+
service_config = opts.delete(:service)
|
|
294
364
|
%i[driver_opts driver_path port].each do |key|
|
|
295
365
|
next unless opts.key? key
|
|
296
366
|
|
|
297
|
-
WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service'
|
|
367
|
+
WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service',
|
|
368
|
+
id: "service_#{key}".to_sym)
|
|
298
369
|
end
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
@service.
|
|
370
|
+
service_config ||= Service.send(browser,
|
|
371
|
+
args: opts.delete(:driver_opts),
|
|
372
|
+
path: opts.delete(:driver_path),
|
|
373
|
+
port: opts.delete(:port))
|
|
374
|
+
@service = service_config.launch
|
|
304
375
|
@service.uri
|
|
305
376
|
end
|
|
377
|
+
|
|
378
|
+
def screenshot
|
|
379
|
+
bridge.screenshot
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def add_extensions(browser)
|
|
383
|
+
extensions = case browser
|
|
384
|
+
when :chrome, :msedge
|
|
385
|
+
Chrome::Driver::EXTENSIONS
|
|
386
|
+
when :firefox
|
|
387
|
+
Firefox::Driver::EXTENSIONS
|
|
388
|
+
when :safari, :safari_technology_preview
|
|
389
|
+
Safari::Driver::EXTENSIONS
|
|
390
|
+
else
|
|
391
|
+
[]
|
|
392
|
+
end
|
|
393
|
+
extensions.each { |extension| extend extension }
|
|
394
|
+
end
|
|
306
395
|
end # Driver
|
|
307
396
|
end # WebDriver
|
|
308
397
|
end # Selenium
|