selenium-webdriver 3.142.7 → 4.10.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 +5 -5
- data/CHANGES +611 -5
- data/Gemfile +5 -1
- data/LICENSE +1 -1
- data/NOTICE +2 -0
- data/README.md +4 -5
- data/bin/linux/selenium-manager +0 -0
- data/bin/macos/selenium-manager +0 -0
- data/bin/windows/selenium-manager.exe +0 -0
- data/lib/selenium/server.rb +94 -79
- data/lib/selenium/webdriver/atoms/findElements.js +121 -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/atoms.rb +2 -3
- data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
- data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
- data/lib/selenium/webdriver/bidi/log/filter_by.rb +40 -0
- data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
- data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
- data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
- data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
- data/lib/selenium/webdriver/bidi/session.rb +51 -0
- data/lib/selenium/webdriver/{common/keyboard.rb → bidi.rb} +21 -35
- data/lib/selenium/webdriver/chrome/driver.rb +9 -86
- data/lib/selenium/webdriver/chrome/features.rb +44 -0
- data/lib/selenium/webdriver/chrome/options.rb +9 -158
- data/lib/selenium/webdriver/chrome/profile.rb +3 -80
- data/lib/selenium/webdriver/chrome/service.rb +6 -33
- data/lib/selenium/webdriver/chrome.rb +5 -18
- data/lib/selenium/webdriver/chromium/driver.rb +61 -0
- data/lib/selenium/webdriver/{chrome/bridge.rb → chromium/features.rb} +51 -16
- data/lib/selenium/webdriver/chromium/options.rb +261 -0
- data/lib/selenium/webdriver/chromium/profile.rb +113 -0
- data/lib/selenium/webdriver/chromium/service.rb +42 -0
- data/lib/selenium/webdriver/chromium.rb +32 -0
- data/lib/selenium/webdriver/common/action_builder.rb +128 -238
- data/lib/selenium/webdriver/common/child_process.rb +124 -0
- data/lib/selenium/webdriver/common/driver.rb +94 -43
- data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +42 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +49 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +87 -0
- data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_bidi.rb} +9 -9
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +86 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +36 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +42 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +41 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +36 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -9
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +143 -0
- data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_logs.rb} +4 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +16 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +69 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -13
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +75 -0
- data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
- data/lib/selenium/webdriver/common/driver_finder.rb +47 -0
- data/lib/selenium/webdriver/common/element.rb +89 -29
- data/lib/selenium/webdriver/common/error.rb +53 -194
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
- data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
- data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -22
- data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +10 -6
- 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 +71 -82
- 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 +59 -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/{w3c_manager.rb → interactions/wheel_input.rb} +14 -17
- data/lib/selenium/webdriver/common/keys.rb +1 -0
- data/lib/selenium/webdriver/common/local_driver.rb +55 -0
- data/lib/selenium/webdriver/common/log_entry.rb +2 -2
- data/lib/selenium/webdriver/common/logger.rb +119 -19
- data/lib/selenium/webdriver/common/manager.rb +11 -38
- data/lib/selenium/webdriver/common/options.rb +169 -23
- data/lib/selenium/webdriver/common/platform.rb +14 -6
- 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 +8 -5
- data/lib/selenium/webdriver/common/search_context.rb +7 -9
- data/lib/selenium/webdriver/common/selenium_manager.rb +125 -0
- data/lib/selenium/webdriver/common/service.rb +26 -137
- data/lib/selenium/webdriver/common/service_manager.rb +144 -0
- data/lib/selenium/webdriver/common/shadow_root.rb +86 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +4 -4
- data/lib/selenium/webdriver/common/socket_poller.rb +4 -4
- data/lib/selenium/webdriver/common/takes_screenshot.rb +65 -0
- data/lib/selenium/webdriver/common/target_locator.rb +31 -4
- data/lib/selenium/webdriver/common/timeouts.rb +31 -4
- data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
- data/lib/selenium/webdriver/common/wait.rb +1 -1
- data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
- data/lib/selenium/webdriver/common/window.rb +6 -10
- data/lib/selenium/webdriver/common/zipper.rb +4 -10
- data/lib/selenium/webdriver/common.rb +42 -18
- data/lib/selenium/webdriver/devtools/console_event.rb +36 -0
- data/lib/selenium/webdriver/devtools/exception_event.rb +34 -0
- data/lib/selenium/webdriver/devtools/mutation_event.rb +35 -0
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
- data/lib/selenium/webdriver/devtools/pinned_script.rb +57 -0
- data/lib/selenium/webdriver/devtools/request.rb +65 -0
- data/lib/selenium/webdriver/devtools/response.rb +64 -0
- data/lib/selenium/webdriver/devtools.rb +96 -0
- data/lib/selenium/webdriver/edge/driver.rb +11 -27
- data/lib/selenium/webdriver/edge/features.rb +44 -0
- data/lib/selenium/webdriver/edge/options.rb +18 -43
- data/lib/selenium/webdriver/edge/profile.rb +33 -0
- data/lib/selenium/webdriver/edge/service.rb +7 -27
- data/lib/selenium/webdriver/edge.rb +11 -14
- data/lib/selenium/webdriver/firefox/driver.rb +38 -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 +77 -50
- data/lib/selenium/webdriver/firefox/profile.rb +17 -71
- data/lib/selenium/webdriver/firefox/service.rb +3 -13
- data/lib/selenium/webdriver/firefox/util.rb +1 -1
- data/lib/selenium/webdriver/firefox.rb +17 -28
- data/lib/selenium/webdriver/ie/driver.rb +5 -45
- data/lib/selenium/webdriver/ie/options.rb +15 -46
- data/lib/selenium/webdriver/ie/service.rb +11 -19
- data/lib/selenium/webdriver/ie.rb +3 -16
- data/lib/selenium/webdriver/remote/bridge/commands.rb +170 -0
- data/lib/selenium/webdriver/remote/bridge.rb +592 -87
- data/lib/selenium/webdriver/remote/capabilities.rb +182 -124
- data/lib/selenium/webdriver/remote/driver.rb +30 -15
- data/lib/selenium/webdriver/remote/http/common.rb +3 -8
- data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
- data/lib/selenium/webdriver/remote/http/default.rb +23 -31
- data/lib/selenium/webdriver/remote/response.rb +17 -49
- data/lib/selenium/webdriver/remote.rb +14 -12
- data/lib/selenium/webdriver/safari/driver.rb +7 -29
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -5
- data/lib/selenium/webdriver/safari/options.rb +12 -27
- data/lib/selenium/webdriver/safari/service.rb +13 -11
- data/lib/selenium/webdriver/safari.rb +14 -20
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
- data/lib/selenium/webdriver/support/color.rb +24 -24
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
- data/lib/selenium/webdriver/support/guards/guard.rb +87 -0
- data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +21 -20
- data/lib/selenium/webdriver/support/guards.rb +95 -0
- data/lib/selenium/webdriver/support/relative_locator.rb +50 -0
- data/lib/selenium/webdriver/support/select.rb +6 -4
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +18 -17
- data/selenium-webdriver.gemspec +36 -18
- metadata +159 -89
- 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/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/http/persistent.rb +0 -60
- 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,236 @@
|
|
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
|
23
|
+
include KeyActions # Actions specific to key inputs
|
24
|
+
include PointerActions # Actions specific to pointer inputs
|
25
|
+
include WheelActions # Actions specific to wheel inputs
|
26
|
+
|
27
|
+
attr_reader :devices
|
28
|
+
|
39
29
|
#
|
40
|
-
#
|
30
|
+
# Initialize a W3C Action Builder. Differs from previous by requiring a bridge and allowing asynchronous actions.
|
31
|
+
# The W3C implementation allows asynchronous actions per device. e.g. A key can be pressed at the same time that
|
32
|
+
# the mouse is moving. Keep in mind that pauses must be added for other devices in order to line up the actions
|
33
|
+
# correctly when using asynchronous.
|
34
|
+
#
|
35
|
+
# @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance.
|
36
|
+
# @param [Selenium::WebDriver::Interactions::PointerInput] deprecated_mouse PointerInput for the mouse.
|
37
|
+
# @param [Selenium::WebDriver::Interactions::KeyInput] deprecated_keyboard KeyInput for the keyboard.
|
38
|
+
# @param [Boolean] deprecated_async Whether to perform the actions asynchronously per device.
|
39
|
+
# Defaults to false for backwards compatibility.
|
40
|
+
# @param [Array<Selenium::WebDriver::Interactions::InputDevices>] devices list of valid sources of input.
|
41
|
+
# @param [Boolean] async Whether to perform the actions asynchronously per device.
|
42
|
+
# @return [ActionBuilder] A self reference.
|
41
43
|
#
|
42
44
|
|
43
|
-
def initialize(
|
44
|
-
@
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
def initialize(bridge, devices: [], async: false, duration: 250)
|
46
|
+
@bridge = bridge
|
47
|
+
@duration = duration
|
48
|
+
@async = async
|
49
|
+
@devices = []
|
48
50
|
|
49
|
-
|
51
|
+
Array(devices).each { |device| add_input(device) }
|
50
52
|
end
|
51
53
|
|
52
54
|
#
|
53
|
-
#
|
54
|
-
# the modifier key - subsequent interactions may assume it's kept pressed.
|
55
|
-
# Note that the modifier key is never released implicitly - either
|
56
|
-
# #key_up(key) or #send_keys(:null) must be called to release the modifier.
|
55
|
+
# Adds a PointerInput device of the given kind
|
57
56
|
#
|
58
|
-
#
|
59
|
-
# driver.action.click(element).send_keys(key)
|
60
|
-
# # or
|
61
|
-
# driver.action.click.send_keys(key)
|
57
|
+
# @example Add a touch pointer input device
|
62
58
|
#
|
63
|
-
#
|
59
|
+
# builder = device.action
|
60
|
+
# builder.add_pointer_input('touch', :touch)
|
64
61
|
#
|
65
|
-
#
|
62
|
+
# @param [String] name name for the device
|
63
|
+
# @param [Symbol] kind kind of pointer device to create
|
64
|
+
# @return [Interactions::PointerInput] The pointer input added
|
66
65
|
#
|
67
|
-
# @example Press a key on an element
|
68
66
|
#
|
69
|
-
# el = driver.find_element(id: "some_id")
|
70
|
-
# driver.action.key_down(el, :shift).perform
|
71
|
-
#
|
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
|
-
|
80
|
-
def key_down(*args)
|
81
|
-
@actions << [:mouse, :click, [args.shift]] if args.first.is_a? Element
|
82
67
|
|
83
|
-
|
84
|
-
|
68
|
+
def add_pointer_input(kind, name)
|
69
|
+
add_input(Interactions.pointer(kind, name: name))
|
85
70
|
end
|
86
71
|
|
87
72
|
#
|
88
|
-
#
|
89
|
-
# Releasing a non-depressed modifier key will yield undefined behaviour.
|
73
|
+
# Adds a KeyInput device
|
90
74
|
#
|
91
|
-
# @example
|
75
|
+
# @example Add a key input device
|
92
76
|
#
|
93
|
-
#
|
77
|
+
# builder = device.action
|
78
|
+
# builder.add_key_input('keyboard2')
|
94
79
|
#
|
95
|
-
# @
|
96
|
-
#
|
97
|
-
# el = driver.find_element(id: "some_id")
|
98
|
-
# driver.action.key_up(el, :alt).perform
|
80
|
+
# @param [String] name name for the device
|
81
|
+
# @return [Interactions::KeyInput] The key input added
|
99
82
|
#
|
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
83
|
|
112
|
-
|
113
|
-
|
84
|
+
def add_key_input(name)
|
85
|
+
add_input(Interactions.key(name))
|
114
86
|
end
|
115
87
|
|
116
88
|
#
|
117
|
-
#
|
118
|
-
# Element#send_keys(keys) on the active element in two ways:
|
89
|
+
# Adds a WheelInput device
|
119
90
|
#
|
120
|
-
#
|
121
|
-
# * There is no attempt to re-focus the element - so send_keys(:tab) for switching elements should work.
|
91
|
+
# @example Add a wheel input device
|
122
92
|
#
|
123
|
-
#
|
93
|
+
# builder = device.action
|
94
|
+
# builder.add_wheel_input('wheel2')
|
124
95
|
#
|
125
|
-
#
|
126
|
-
#
|
96
|
+
# @param [String] name name for the device
|
97
|
+
# @return [Interactions::WheelInput] The wheel input added
|
127
98
|
#
|
128
|
-
|
99
|
+
|
100
|
+
def add_wheel_input(name)
|
101
|
+
add_input(Interactions.wheel(name))
|
102
|
+
end
|
103
|
+
|
129
104
|
#
|
130
|
-
#
|
105
|
+
# Retrieves the input device for the given name or type
|
131
106
|
#
|
132
|
-
# @
|
133
|
-
#
|
134
|
-
# @
|
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
|
107
|
+
# @param [String] name name of the input device
|
108
|
+
# @param [String] type name of the input device
|
109
|
+
# @return [Selenium::WebDriver::Interactions::InputDevice] input device with given name or type
|
138
110
|
#
|
139
111
|
|
140
|
-
def
|
141
|
-
@
|
112
|
+
def device(name: nil, type: nil)
|
113
|
+
input = @devices.find { |device| (device.name == name.to_s || name.nil?) && (device.type == type || type.nil?) }
|
142
114
|
|
143
|
-
|
144
|
-
|
115
|
+
raise(ArgumentError, "Can not find device: #{name}") if name && input.nil?
|
116
|
+
|
117
|
+
input
|
145
118
|
end
|
146
119
|
|
147
120
|
#
|
148
|
-
#
|
149
|
-
# equivalent to:
|
121
|
+
# Retrieves the current PointerInput devices
|
150
122
|
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# @example Clicking and holding on some element
|
154
|
-
#
|
155
|
-
# el = driver.find_element(id: "some_id")
|
156
|
-
# driver.action.click_and_hold(el).perform
|
157
|
-
#
|
158
|
-
# @param [Element] element the element to move to and click.
|
159
|
-
# @return [ActionBuilder] A self reference.
|
123
|
+
# @return [Array] array of current PointerInput devices
|
160
124
|
#
|
161
125
|
|
162
|
-
def
|
163
|
-
@
|
164
|
-
self
|
126
|
+
def pointer_inputs
|
127
|
+
@devices.select { |device| device.type == Interactions::POINTER }
|
165
128
|
end
|
166
129
|
|
167
130
|
#
|
168
|
-
#
|
131
|
+
# Retrieves the current KeyInput device
|
169
132
|
#
|
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.
|
133
|
+
# @return [Selenium::WebDriver::Interactions::InputDevice] current KeyInput device
|
176
134
|
#
|
177
135
|
|
178
|
-
def
|
179
|
-
@
|
180
|
-
self
|
136
|
+
def key_inputs
|
137
|
+
@devices.select { |device| device.type == Interactions::KEY }
|
181
138
|
end
|
182
139
|
|
183
140
|
#
|
184
|
-
#
|
141
|
+
# Retrieves the current WheelInput device
|
185
142
|
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
# When no element is passed, the current mouse position will be clicked.
|
189
|
-
#
|
190
|
-
# @example Clicking on an element
|
191
|
-
#
|
192
|
-
# el = driver.find_element(id: "some_id")
|
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.
|
143
|
+
# @return [Selenium::WebDriver::Interactions::InputDevice] current WheelInput devices
|
201
144
|
#
|
202
145
|
|
203
|
-
def
|
204
|
-
@
|
205
|
-
self
|
146
|
+
def wheel_inputs
|
147
|
+
@devices.select { |device| device.type == Interactions::WHEEL }
|
206
148
|
end
|
207
149
|
|
208
150
|
#
|
209
|
-
#
|
210
|
-
#
|
211
|
-
# driver.action.move_to(element).double_click
|
151
|
+
# Creates a pause for the given device of the given duration. If no duration is given, the pause will only wait
|
152
|
+
# for all actions to complete in that tick.
|
212
153
|
#
|
213
|
-
# @example
|
154
|
+
# @example Send keys to an element
|
214
155
|
#
|
215
|
-
#
|
216
|
-
#
|
156
|
+
# action_builder = driver.action
|
157
|
+
# keyboard = action_builder.key_input
|
158
|
+
# el = driver.find_element(id: "some_id")
|
159
|
+
# driver.action.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys').perform
|
217
160
|
#
|
218
|
-
# @param [
|
161
|
+
# @param [InputDevice] device Input device to pause
|
162
|
+
# @param [Float] duration Duration to pause
|
219
163
|
# @return [ActionBuilder] A self reference.
|
220
164
|
#
|
221
165
|
|
222
|
-
def
|
223
|
-
|
166
|
+
def pause(device: nil, duration: 0)
|
167
|
+
device ||= pointer_input
|
168
|
+
device.create_pause(duration)
|
224
169
|
self
|
225
170
|
end
|
226
171
|
|
227
172
|
#
|
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
|
235
|
-
#
|
236
|
-
# el = driver.find_element(id: "some_id")
|
237
|
-
# driver.action.move_to(el).perform
|
173
|
+
# Creates multiple pauses for the given device of the given duration.
|
238
174
|
#
|
239
|
-
# @example
|
175
|
+
# @example Send keys to an element
|
240
176
|
#
|
177
|
+
# action_builder = driver.action
|
178
|
+
# keyboard = action_builder.key_input
|
241
179
|
# el = driver.find_element(id: "some_id")
|
242
|
-
# driver.action.
|
180
|
+
# driver.action.click(el).pauses(keyboard, 3).send_keys('keys').perform
|
243
181
|
#
|
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.
|
182
|
+
# @param [InputDevice] device Input device to pause
|
183
|
+
# @param [Integer] number of pauses to add for the device
|
184
|
+
# @param [Float] duration Duration to pause
|
249
185
|
# @return [ActionBuilder] A self reference.
|
250
186
|
#
|
251
187
|
|
252
|
-
def
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
[:mouse, :move_to, [element]]
|
257
|
-
end
|
188
|
+
def pauses(device: nil, number: nil, duration: 0)
|
189
|
+
number ||= 2
|
190
|
+
device ||= pointer_input
|
191
|
+
duration ||= 0
|
258
192
|
|
193
|
+
number.times { device.create_pause(duration) }
|
259
194
|
self
|
260
195
|
end
|
261
196
|
|
262
197
|
#
|
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.
|
198
|
+
# Executes the actions added to the builder.
|
279
199
|
#
|
280
200
|
|
281
|
-
def
|
282
|
-
@
|
283
|
-
|
201
|
+
def perform
|
202
|
+
@bridge.send_actions @devices.filter_map(&:encode)
|
203
|
+
clear_all_actions
|
204
|
+
nil
|
284
205
|
end
|
285
206
|
|
286
207
|
#
|
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.
|
208
|
+
# Clears all actions from the builder.
|
297
209
|
#
|
298
210
|
|
299
|
-
def
|
300
|
-
@
|
301
|
-
self
|
211
|
+
def clear_all_actions
|
212
|
+
@devices.each(&:clear_actions)
|
302
213
|
end
|
303
214
|
|
304
215
|
#
|
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.
|
216
|
+
# Releases all action states from the browser.
|
319
217
|
#
|
320
218
|
|
321
|
-
def
|
322
|
-
|
323
|
-
move_to target
|
324
|
-
release
|
325
|
-
|
326
|
-
self
|
219
|
+
def release_actions
|
220
|
+
@bridge.release_actions
|
327
221
|
end
|
328
222
|
|
223
|
+
private
|
224
|
+
|
329
225
|
#
|
330
|
-
#
|
331
|
-
# the source element, moves by a given offset, then releases the mouse.
|
332
|
-
#
|
333
|
-
# @example Drag and drop an element by offset
|
334
|
-
#
|
335
|
-
# el = driver.find_element(id: "some_id1")
|
336
|
-
# driver.action.drag_and_drop_by(el, 100, 100).perform
|
226
|
+
# Adds pauses for all devices but the given devices
|
337
227
|
#
|
338
|
-
# @param [
|
339
|
-
# @param [Integer] right_by horizontal move offset.
|
340
|
-
# @param [Integer] down_by vertical move offset.
|
341
|
-
# @return [ActionBuilder] A self reference.
|
228
|
+
# @param [Array[InputDevice]] action_devices Array of Input Devices performing an action in this tick.
|
342
229
|
#
|
343
230
|
|
344
|
-
def
|
345
|
-
|
346
|
-
move_by right_by, down_by
|
347
|
-
release
|
231
|
+
def tick(*action_devices)
|
232
|
+
return if @async
|
348
233
|
|
349
|
-
|
234
|
+
@devices.each { |device| device.create_pause unless action_devices.include? device }
|
350
235
|
end
|
351
236
|
|
352
237
|
#
|
353
|
-
#
|
238
|
+
# Adds an InputDevice
|
354
239
|
#
|
355
240
|
|
356
|
-
def
|
357
|
-
|
358
|
-
@devices.fetch(receiver).__send__(method, *args)
|
359
|
-
end
|
241
|
+
def add_input(device)
|
242
|
+
device = Interactions.send(device) if device.is_a?(Symbol) && Interactions.respond_to?(device)
|
360
243
|
|
361
|
-
|
244
|
+
raise TypeError, "#{device.inspect} is not a valid InputDevice" unless device.is_a?(Interactions::InputDevice)
|
245
|
+
|
246
|
+
unless @async
|
247
|
+
max_device = @devices.max { |a, b| a.actions.length <=> b.actions.length }
|
248
|
+
pauses(device: device, number: max_device.actions.length) if max_device
|
249
|
+
end
|
250
|
+
@devices << device
|
251
|
+
device
|
362
252
|
end
|
363
253
|
end # ActionBuilder
|
364
254
|
end # WebDriver
|
@@ -0,0 +1,124 @@
|
|
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
|
+
#
|
23
|
+
# @api private
|
24
|
+
#
|
25
|
+
|
26
|
+
class ChildProcess
|
27
|
+
TimeoutError = Class.new(StandardError)
|
28
|
+
|
29
|
+
SIGTERM = 'TERM'
|
30
|
+
SIGKILL = 'KILL'
|
31
|
+
|
32
|
+
POLL_INTERVAL = 0.1
|
33
|
+
|
34
|
+
attr_accessor :detach
|
35
|
+
attr_writer :io
|
36
|
+
|
37
|
+
def self.build(*command)
|
38
|
+
new(*command)
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(*command)
|
42
|
+
@command = command
|
43
|
+
@detach = false
|
44
|
+
@pid = nil
|
45
|
+
@status = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def io
|
49
|
+
@io ||= Platform.null_device
|
50
|
+
end
|
51
|
+
|
52
|
+
def start
|
53
|
+
options = {%i[out err] => io}
|
54
|
+
options[:pgroup] = true unless Platform.windows? # NOTE: this is a bug only in Windows 7
|
55
|
+
|
56
|
+
WebDriver.logger.debug("Starting process: #{@command} with #{options}", id: :process)
|
57
|
+
@pid = Process.spawn(*@command, options)
|
58
|
+
WebDriver.logger.debug(" -> pid: #{@pid}", id: :process)
|
59
|
+
|
60
|
+
Process.detach(@pid) if detach
|
61
|
+
end
|
62
|
+
|
63
|
+
def stop(timeout = 3)
|
64
|
+
return unless @pid
|
65
|
+
return if exited?
|
66
|
+
|
67
|
+
WebDriver.logger.debug("Sending TERM to process: #{@pid}", id: :process)
|
68
|
+
terminate(@pid)
|
69
|
+
poll_for_exit(timeout)
|
70
|
+
|
71
|
+
WebDriver.logger.debug(" -> stopped #{@pid}", id: :process)
|
72
|
+
rescue TimeoutError, Errno::EINVAL
|
73
|
+
WebDriver.logger.debug(" -> sending KILL to process: #{@pid}", id: :process)
|
74
|
+
kill(@pid)
|
75
|
+
wait
|
76
|
+
WebDriver.logger.debug(" -> killed #{@pid}", id: :process)
|
77
|
+
end
|
78
|
+
|
79
|
+
def alive?
|
80
|
+
@pid && !exited?
|
81
|
+
end
|
82
|
+
|
83
|
+
def exited?
|
84
|
+
return unless @pid
|
85
|
+
|
86
|
+
WebDriver.logger.debug("Checking if #{@pid} is exited:", id: :process)
|
87
|
+
_, @status = Process.waitpid2(@pid, Process::WNOHANG | Process::WUNTRACED) if @status.nil?
|
88
|
+
return if @status.nil?
|
89
|
+
|
90
|
+
exit_code = @status.exitstatus || @status.termsig
|
91
|
+
WebDriver.logger.debug(" -> exit code is #{exit_code.inspect}", id: :process)
|
92
|
+
|
93
|
+
!!exit_code
|
94
|
+
end
|
95
|
+
|
96
|
+
def poll_for_exit(timeout)
|
97
|
+
WebDriver.logger.debug("Polling #{timeout} seconds for exit of #{@pid}", id: :process)
|
98
|
+
|
99
|
+
end_time = Time.now + timeout
|
100
|
+
sleep POLL_INTERVAL until exited? || Time.now > end_time
|
101
|
+
|
102
|
+
raise TimeoutError, " -> #{@pid} still alive after #{timeout} seconds" unless exited?
|
103
|
+
end
|
104
|
+
|
105
|
+
def wait
|
106
|
+
return if exited?
|
107
|
+
|
108
|
+
_, @status = Process.waitpid2(@pid)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def terminate(pid)
|
114
|
+
Process.kill(SIGTERM, pid)
|
115
|
+
end
|
116
|
+
|
117
|
+
def kill(pid)
|
118
|
+
Process.kill(SIGKILL, pid)
|
119
|
+
rescue Errno::ECHILD, Errno::ESRCH
|
120
|
+
# already dead
|
121
|
+
end
|
122
|
+
end # ChildProcess
|
123
|
+
end # WebDriver
|
124
|
+
end # Selenium
|