selenium-webdriver 3.142.7 → 4.16.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 +685 -5
- data/Gemfile +6 -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 +93 -90
- 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 +77 -78
- data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
- data/lib/selenium/webdriver/atoms.rb +5 -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 +48 -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 +7 -29
- data/lib/selenium/webdriver/chrome.rb +5 -20
- data/lib/selenium/webdriver/chromium/driver.rb +60 -0
- data/lib/selenium/webdriver/{chrome/bridge.rb → chromium/features.rb} +48 -17
- data/lib/selenium/webdriver/chromium/options.rb +243 -0
- data/lib/selenium/webdriver/chromium/profile.rb +113 -0
- data/lib/selenium/webdriver/chromium.rb +29 -0
- data/lib/selenium/webdriver/common/action_builder.rb +126 -238
- data/lib/selenium/webdriver/common/child_process.rb +124 -0
- data/lib/selenium/webdriver/common/driver.rb +82 -43
- data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/{has_location.rb → full_page_screenshot.rb} +13 -11
- 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_file_downloads.rb +65 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +36 -0
- 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_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 +45 -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 +46 -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 +154 -23
- data/lib/selenium/webdriver/common/platform.rb +15 -52
- 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 +140 -0
- data/lib/selenium/webdriver/common/service.rb +26 -143
- 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 +43 -20
- 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 +48 -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 +8 -23
- data/lib/selenium/webdriver/edge.rb +11 -16
- 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 +70 -0
- data/lib/selenium/webdriver/firefox/options.rb +73 -61
- data/lib/selenium/webdriver/firefox/profile.rb +20 -72
- data/lib/selenium/webdriver/firefox/service.rb +3 -25
- 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/features.rb +34 -0
- data/lib/selenium/webdriver/ie/options.rb +14 -44
- data/lib/selenium/webdriver/ie/service.rb +3 -27
- data/lib/selenium/webdriver/ie.rb +4 -16
- data/lib/selenium/webdriver/remote/bridge/commands.rb +164 -0
- data/lib/selenium/webdriver/remote/bridge.rb +574 -88
- data/lib/selenium/webdriver/remote/capabilities.rb +144 -158
- data/lib/selenium/webdriver/remote/driver.rb +45 -14
- data/lib/selenium/webdriver/remote/features.rb +75 -0
- 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 +24 -33
- data/lib/selenium/webdriver/remote/response.rb +17 -49
- data/lib/selenium/webdriver/remote/server_error.rb +1 -1
- data/lib/selenium/webdriver/remote.rb +15 -12
- data/lib/selenium/webdriver/safari/driver.rb +7 -29
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +7 -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 +5 -5
- data/lib/selenium/webdriver/support/guards/guard.rb +90 -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 +19 -17
- data/selenium-webdriver.gemspec +36 -18
- metadata +161 -91
- data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +0 -58
- 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
|
@@ -21,128 +21,562 @@ module Selenium
|
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Remote
|
|
23
23
|
class Bridge
|
|
24
|
+
autoload :COMMANDS, 'selenium/webdriver/remote/bridge/commands'
|
|
24
25
|
include Atoms
|
|
25
|
-
include BridgeHelper
|
|
26
26
|
|
|
27
27
|
PORT = 4444
|
|
28
|
-
COMMANDS = {
|
|
29
|
-
new_session: [:post, 'session']
|
|
30
|
-
}.freeze
|
|
31
28
|
|
|
32
|
-
attr_accessor :
|
|
33
|
-
attr_reader :capabilities
|
|
29
|
+
attr_accessor :http, :file_detector
|
|
30
|
+
attr_reader :capabilities
|
|
34
31
|
|
|
35
32
|
#
|
|
36
|
-
#
|
|
33
|
+
# Initializes the bridge with the given server URL
|
|
34
|
+
# @param [String, URI] url url for the remote server
|
|
35
|
+
# @param [Object] http_client an HTTP client instance that implements the same protocol as Http::Default
|
|
36
|
+
# @api private
|
|
37
37
|
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
|
|
39
|
+
def initialize(url:, http_client: nil)
|
|
40
|
+
uri = url.is_a?(URI) ? url : URI.parse(url)
|
|
41
|
+
uri.path += '/' unless uri.path.end_with?('/')
|
|
42
|
+
|
|
43
|
+
@http = http_client || Http::Default.new
|
|
44
|
+
@http.server_url = uri
|
|
45
|
+
@file_detector = nil
|
|
46
|
+
end
|
|
47
|
+
|
|
41
48
|
#
|
|
42
|
-
#
|
|
49
|
+
# Creates session.
|
|
43
50
|
#
|
|
44
|
-
def self.handshake(**opts)
|
|
45
|
-
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
|
|
50
|
-
end
|
|
52
|
+
def create_session(capabilities)
|
|
53
|
+
response = execute(:new_session, {}, prepare_capabilities_payload(capabilities))
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
@session_id = response['sessionId']
|
|
56
|
+
capabilities = response['capabilities']
|
|
57
|
+
|
|
58
|
+
raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
|
|
59
|
+
|
|
60
|
+
@capabilities = Capabilities.json_create(capabilities)
|
|
61
|
+
|
|
62
|
+
case @capabilities[:browser_name]
|
|
63
|
+
when 'chrome'
|
|
64
|
+
extend(WebDriver::Chrome::Features)
|
|
65
|
+
when 'firefox'
|
|
66
|
+
extend(WebDriver::Firefox::Features)
|
|
67
|
+
when 'msedge'
|
|
68
|
+
extend(WebDriver::Edge::Features)
|
|
69
|
+
when 'Safari', 'Safari Technology Preview'
|
|
70
|
+
extend(WebDriver::Safari::Features)
|
|
53
71
|
end
|
|
72
|
+
end
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
|
|
74
|
+
#
|
|
75
|
+
# Returns the current session ID.
|
|
76
|
+
#
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
def session_id
|
|
79
|
+
@session_id || raise(Error::WebDriverError, 'no current session exists')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def browser
|
|
83
|
+
@browser ||= begin
|
|
84
|
+
name = @capabilities.browser_name
|
|
85
|
+
name ? name.tr(' ', '_').downcase.to_sym : 'unknown'
|
|
65
86
|
end
|
|
66
87
|
end
|
|
67
88
|
|
|
89
|
+
def status
|
|
90
|
+
execute :status
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def get(url)
|
|
94
|
+
execute :get, {}, {url: url}
|
|
95
|
+
end
|
|
96
|
+
|
|
68
97
|
#
|
|
69
|
-
#
|
|
70
|
-
# @param [Hash] opts options for the driver
|
|
71
|
-
# @option opts [String] :url url for the remote server
|
|
72
|
-
# @option opts [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
|
|
73
|
-
# @option opts [Capabilities] :desired_capabilities an instance of Remote::Capabilities describing the capabilities you want
|
|
74
|
-
# @api private
|
|
98
|
+
# timeouts
|
|
75
99
|
#
|
|
76
100
|
|
|
77
|
-
def
|
|
78
|
-
|
|
101
|
+
def timeouts
|
|
102
|
+
execute :get_timeouts, {}
|
|
103
|
+
end
|
|
79
104
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
105
|
+
def timeouts=(timeouts)
|
|
106
|
+
execute :set_timeout, {}, timeouts
|
|
107
|
+
end
|
|
83
108
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
#
|
|
110
|
+
# alerts
|
|
111
|
+
#
|
|
87
112
|
|
|
88
|
-
|
|
89
|
-
|
|
113
|
+
def accept_alert
|
|
114
|
+
execute :accept_alert
|
|
115
|
+
end
|
|
90
116
|
|
|
91
|
-
|
|
117
|
+
def dismiss_alert
|
|
118
|
+
execute :dismiss_alert
|
|
119
|
+
end
|
|
92
120
|
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
def alert=(keys)
|
|
122
|
+
execute :send_alert_text, {}, {value: keys.chars, text: keys}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def alert_text
|
|
126
|
+
execute :get_alert_text
|
|
95
127
|
end
|
|
96
128
|
|
|
97
129
|
#
|
|
98
|
-
#
|
|
130
|
+
# navigation
|
|
99
131
|
#
|
|
100
132
|
|
|
101
|
-
def
|
|
102
|
-
|
|
133
|
+
def go_back
|
|
134
|
+
execute :back
|
|
135
|
+
end
|
|
103
136
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
137
|
+
def go_forward
|
|
138
|
+
execute :forward
|
|
139
|
+
end
|
|
107
140
|
|
|
108
|
-
|
|
109
|
-
|
|
141
|
+
def url
|
|
142
|
+
execute :get_current_url
|
|
143
|
+
end
|
|
110
144
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
def title
|
|
146
|
+
execute :get_title
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def page_source
|
|
150
|
+
execute :get_page_source
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
# Create a new top-level browsing context
|
|
155
|
+
# https://w3c.github.io/webdriver/#new-window
|
|
156
|
+
# @param type [String] Supports two values: 'tab' and 'window'.
|
|
157
|
+
# Use 'tab' if you'd like the new window to share an OS-level window
|
|
158
|
+
# with the current browsing context.
|
|
159
|
+
# Use 'window' otherwise
|
|
160
|
+
# @return [Hash] Containing 'handle' with the value of the window handle
|
|
161
|
+
# and 'type' with the value of the created window type
|
|
162
|
+
#
|
|
163
|
+
def new_window(type)
|
|
164
|
+
execute :new_window, {}, {type: type}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def switch_to_window(name)
|
|
168
|
+
execute :switch_to_window, {}, {handle: name}
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def switch_to_frame(id)
|
|
172
|
+
id = find_element_by('id', id) if id.is_a? String
|
|
173
|
+
execute :switch_to_frame, {}, {id: id}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def switch_to_parent_frame
|
|
177
|
+
execute :switch_to_parent_frame
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def switch_to_default_content
|
|
181
|
+
switch_to_frame nil
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
QUIT_ERRORS = [IOError].freeze
|
|
185
|
+
|
|
186
|
+
def quit
|
|
187
|
+
execute :delete_session
|
|
188
|
+
http.close
|
|
189
|
+
rescue *QUIT_ERRORS
|
|
190
|
+
nil
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def close
|
|
194
|
+
execute :close_window
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def refresh
|
|
198
|
+
execute :refresh
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
#
|
|
202
|
+
# window handling
|
|
203
|
+
#
|
|
204
|
+
|
|
205
|
+
def window_handles
|
|
206
|
+
execute :get_window_handles
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def window_handle
|
|
210
|
+
execute :get_window_handle
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def resize_window(width, height, handle = :current)
|
|
214
|
+
raise Error::WebDriverError, 'Switch to desired window before changing its size' unless handle == :current
|
|
215
|
+
|
|
216
|
+
set_window_rect(width: width, height: height)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def window_size(handle = :current)
|
|
220
|
+
unless handle == :current
|
|
221
|
+
raise Error::UnsupportedOperationError,
|
|
222
|
+
'Switch to desired window before getting its size'
|
|
116
223
|
end
|
|
117
224
|
|
|
118
|
-
|
|
225
|
+
data = execute :get_window_rect
|
|
226
|
+
Dimension.new data['width'], data['height']
|
|
227
|
+
end
|
|
119
228
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
229
|
+
def minimize_window
|
|
230
|
+
execute :minimize_window
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def maximize_window(handle = :current)
|
|
234
|
+
unless handle == :current
|
|
235
|
+
raise Error::UnsupportedOperationError,
|
|
236
|
+
'Switch to desired window before changing its size'
|
|
128
237
|
end
|
|
238
|
+
|
|
239
|
+
execute :maximize_window
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def full_screen_window
|
|
243
|
+
execute :fullscreen_window
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def reposition_window(x, y)
|
|
247
|
+
set_window_rect(x: x, y: y)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def window_position
|
|
251
|
+
data = execute :get_window_rect
|
|
252
|
+
Point.new data['x'], data['y']
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def set_window_rect(x: nil, y: nil, width: nil, height: nil)
|
|
256
|
+
params = {x: x, y: y, width: width, height: height}
|
|
257
|
+
params.update(params) { |_k, v| Integer(v) unless v.nil? }
|
|
258
|
+
execute :set_window_rect, {}, params
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def window_rect
|
|
262
|
+
data = execute :get_window_rect
|
|
263
|
+
Rectangle.new data['x'], data['y'], data['width'], data['height']
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def screenshot
|
|
267
|
+
execute :take_screenshot
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def element_screenshot(element)
|
|
271
|
+
execute :take_element_screenshot, id: element
|
|
129
272
|
end
|
|
130
273
|
|
|
131
274
|
#
|
|
132
|
-
#
|
|
275
|
+
# HTML 5
|
|
133
276
|
#
|
|
134
277
|
|
|
135
|
-
def
|
|
136
|
-
|
|
278
|
+
def local_storage_item(key, value = nil)
|
|
279
|
+
if value
|
|
280
|
+
execute_script("localStorage.setItem('#{key}', '#{value}')")
|
|
281
|
+
else
|
|
282
|
+
execute_script("return localStorage.getItem('#{key}')")
|
|
283
|
+
end
|
|
137
284
|
end
|
|
138
285
|
|
|
139
|
-
def
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
286
|
+
def remove_local_storage_item(key)
|
|
287
|
+
execute_script("localStorage.removeItem('#{key}')")
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def local_storage_keys
|
|
291
|
+
execute_script('return Object.keys(localStorage)')
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def clear_local_storage
|
|
295
|
+
execute_script('localStorage.clear()')
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def local_storage_size
|
|
299
|
+
execute_script('return localStorage.length')
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def session_storage_item(key, value = nil)
|
|
303
|
+
if value
|
|
304
|
+
execute_script("sessionStorage.setItem('#{key}', '#{value}')")
|
|
305
|
+
else
|
|
306
|
+
execute_script("return sessionStorage.getItem('#{key}')")
|
|
143
307
|
end
|
|
144
308
|
end
|
|
145
309
|
|
|
310
|
+
def remove_session_storage_item(key)
|
|
311
|
+
execute_script("sessionStorage.removeItem('#{key}')")
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def session_storage_keys
|
|
315
|
+
execute_script('return Object.keys(sessionStorage)')
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def clear_session_storage
|
|
319
|
+
execute_script('sessionStorage.clear()')
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def session_storage_size
|
|
323
|
+
execute_script('return sessionStorage.length')
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
#
|
|
327
|
+
# javascript execution
|
|
328
|
+
#
|
|
329
|
+
|
|
330
|
+
def execute_script(script, *args)
|
|
331
|
+
result = execute :execute_script, {}, {script: script, args: args}
|
|
332
|
+
unwrap_script_result result
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def execute_async_script(script, *args)
|
|
336
|
+
result = execute :execute_async_script, {}, {script: script, args: args}
|
|
337
|
+
unwrap_script_result result
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
#
|
|
341
|
+
# cookies
|
|
342
|
+
#
|
|
343
|
+
|
|
344
|
+
def manage
|
|
345
|
+
@manage ||= WebDriver::Manager.new(self)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def add_cookie(cookie)
|
|
349
|
+
execute :add_cookie, {}, {cookie: cookie}
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def delete_cookie(name)
|
|
353
|
+
execute :delete_cookie, name: name
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def cookie(name)
|
|
357
|
+
execute :get_cookie, name: name
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def cookies
|
|
361
|
+
execute :get_all_cookies
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def delete_all_cookies
|
|
365
|
+
execute :delete_all_cookies
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
#
|
|
369
|
+
# actions
|
|
370
|
+
#
|
|
371
|
+
|
|
372
|
+
def action(async: false, devices: [], duration: 250)
|
|
373
|
+
ActionBuilder.new self, async: async, devices: devices, duration: duration
|
|
374
|
+
end
|
|
375
|
+
alias actions action
|
|
376
|
+
|
|
377
|
+
def send_actions(data)
|
|
378
|
+
execute :actions, {}, {actions: data}
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def release_actions
|
|
382
|
+
execute :release_actions
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def print_page(options = {})
|
|
386
|
+
execute :print_page, {}, {options: options}
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def click_element(element)
|
|
390
|
+
execute :element_click, id: element
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def send_keys_to_element(element, keys)
|
|
394
|
+
keys = upload_if_necessary(keys) if @file_detector
|
|
395
|
+
text = keys.join
|
|
396
|
+
execute :element_send_keys, {id: element}, {value: text.chars, text: text}
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def clear_element(element)
|
|
400
|
+
execute :element_clear, id: element
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def submit_element(element)
|
|
404
|
+
script = "/* submitForm */ var form = arguments[0];\n" \
|
|
405
|
+
"while (form.nodeName != \"FORM\" && form.parentNode) {\n " \
|
|
406
|
+
"form = form.parentNode;\n" \
|
|
407
|
+
"}\n" \
|
|
408
|
+
"if (!form) { throw Error('Unable to find containing form element'); }\n" \
|
|
409
|
+
"if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" \
|
|
410
|
+
"var e = form.ownerDocument.createEvent('Event');\n" \
|
|
411
|
+
"e.initEvent('submit', true, true);\n" \
|
|
412
|
+
"if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n"
|
|
413
|
+
|
|
414
|
+
execute_script(script, Element::ELEMENT_KEY => element)
|
|
415
|
+
rescue Error::JavascriptError
|
|
416
|
+
raise Error::UnsupportedOperationError, 'To submit an element, it must be nested inside a form element'
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
#
|
|
420
|
+
# element properties
|
|
421
|
+
#
|
|
422
|
+
|
|
423
|
+
def element_tag_name(element)
|
|
424
|
+
execute :get_element_tag_name, id: element
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def element_attribute(element, name)
|
|
428
|
+
WebDriver.logger.debug "Using script for :getAttribute of #{name}", id: :script
|
|
429
|
+
execute_atom :getAttribute, element, name
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def element_dom_attribute(element, name)
|
|
433
|
+
execute :get_element_attribute, id: element, name: name
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def element_property(element, name)
|
|
437
|
+
execute :get_element_property, id: element, name: name
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def element_aria_role(element)
|
|
441
|
+
execute :get_element_aria_role, id: element
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def element_aria_label(element)
|
|
445
|
+
execute :get_element_aria_label, id: element
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def element_value(element)
|
|
449
|
+
element_property element, 'value'
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def element_text(element)
|
|
453
|
+
execute :get_element_text, id: element
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def element_location(element)
|
|
457
|
+
data = execute :get_element_rect, id: element
|
|
458
|
+
|
|
459
|
+
Point.new data['x'], data['y']
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def element_rect(element)
|
|
463
|
+
data = execute :get_element_rect, id: element
|
|
464
|
+
|
|
465
|
+
Rectangle.new data['x'], data['y'], data['width'], data['height']
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
def element_location_once_scrolled_into_view(element)
|
|
469
|
+
send_keys_to_element(element, [''])
|
|
470
|
+
element_location(element)
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def element_size(element)
|
|
474
|
+
data = execute :get_element_rect, id: element
|
|
475
|
+
|
|
476
|
+
Dimension.new data['width'], data['height']
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def element_enabled?(element)
|
|
480
|
+
execute :is_element_enabled, id: element
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def element_selected?(element)
|
|
484
|
+
execute :is_element_selected, id: element
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
def element_displayed?(element)
|
|
488
|
+
WebDriver.logger.debug 'Using script for :isDisplayed', id: :script
|
|
489
|
+
execute_atom :isDisplayed, element
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def element_value_of_css_property(element, prop)
|
|
493
|
+
execute :get_element_css_value, id: element, property_name: prop
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
#
|
|
497
|
+
# finding elements
|
|
498
|
+
#
|
|
499
|
+
|
|
500
|
+
def active_element
|
|
501
|
+
Element.new self, element_id_from(execute(:get_active_element))
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
alias switch_to_active_element active_element
|
|
505
|
+
|
|
506
|
+
def find_element_by(how, what, parent_ref = [])
|
|
507
|
+
how, what = convert_locator(how, what)
|
|
508
|
+
|
|
509
|
+
return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
|
|
510
|
+
|
|
511
|
+
parent_type, parent_id = parent_ref
|
|
512
|
+
id = case parent_type
|
|
513
|
+
when :element
|
|
514
|
+
execute :find_child_element, {id: parent_id}, {using: how, value: what.to_s}
|
|
515
|
+
when :shadow_root
|
|
516
|
+
execute :find_shadow_child_element, {id: parent_id}, {using: how, value: what.to_s}
|
|
517
|
+
else
|
|
518
|
+
execute :find_element, {}, {using: how, value: what.to_s}
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
Element.new self, element_id_from(id)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
def find_elements_by(how, what, parent_ref = [])
|
|
525
|
+
how, what = convert_locator(how, what)
|
|
526
|
+
|
|
527
|
+
return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
|
|
528
|
+
|
|
529
|
+
parent_type, parent_id = parent_ref
|
|
530
|
+
ids = case parent_type
|
|
531
|
+
when :element
|
|
532
|
+
execute :find_child_elements, {id: parent_id}, {using: how, value: what.to_s}
|
|
533
|
+
when :shadow_root
|
|
534
|
+
execute :find_shadow_child_elements, {id: parent_id}, {using: how, value: what.to_s}
|
|
535
|
+
else
|
|
536
|
+
execute :find_elements, {}, {using: how, value: what.to_s}
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
ids.map { |id| Element.new self, element_id_from(id) }
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def shadow_root(element)
|
|
543
|
+
id = execute :get_element_shadow_root, id: element
|
|
544
|
+
ShadowRoot.new self, shadow_root_id_from(id)
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
#
|
|
548
|
+
# virtual-authenticator
|
|
549
|
+
#
|
|
550
|
+
|
|
551
|
+
def add_virtual_authenticator(options)
|
|
552
|
+
authenticator_id = execute :add_virtual_authenticator, {}, options.as_json
|
|
553
|
+
VirtualAuthenticator.new(self, authenticator_id, options)
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
def remove_virtual_authenticator(id)
|
|
557
|
+
execute :remove_virtual_authenticator, {authenticatorId: id}
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def add_credential(credential, id)
|
|
561
|
+
execute :add_credential, {authenticatorId: id}, credential
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def credentials(authenticator_id)
|
|
565
|
+
execute :get_credentials, {authenticatorId: authenticator_id}
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def remove_credential(credential_id, authenticator_id)
|
|
569
|
+
execute :remove_credential, {credentialId: credential_id, authenticatorId: authenticator_id}
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def remove_all_credentials(authenticator_id)
|
|
573
|
+
execute :remove_all_credentials, {authenticatorId: authenticator_id}
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
def user_verified(verified, authenticator_id)
|
|
577
|
+
execute :set_user_verified, {authenticatorId: authenticator_id}, {isUserVerified: verified}
|
|
578
|
+
end
|
|
579
|
+
|
|
146
580
|
private
|
|
147
581
|
|
|
148
582
|
#
|
|
@@ -163,8 +597,8 @@ module Selenium
|
|
|
163
597
|
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
|
164
598
|
end
|
|
165
599
|
|
|
166
|
-
WebDriver.logger.
|
|
167
|
-
http.call(verb, path, command_hash)
|
|
600
|
+
WebDriver.logger.debug("-> #{verb.to_s.upcase} #{path}", id: :command)
|
|
601
|
+
http.call(verb, path, command_hash)['value']
|
|
168
602
|
end
|
|
169
603
|
|
|
170
604
|
def escaper
|
|
@@ -172,23 +606,75 @@ module Selenium
|
|
|
172
606
|
end
|
|
173
607
|
|
|
174
608
|
def commands(command)
|
|
175
|
-
raise NotImplementedError unless command == :new_session
|
|
176
|
-
|
|
177
609
|
COMMANDS[command]
|
|
178
610
|
end
|
|
179
611
|
|
|
180
|
-
def
|
|
181
|
-
|
|
182
|
-
|
|
612
|
+
def unwrap_script_result(arg)
|
|
613
|
+
case arg
|
|
614
|
+
when Array
|
|
615
|
+
arg.map { |e| unwrap_script_result(e) }
|
|
616
|
+
when Hash
|
|
617
|
+
element_id = element_id_from(arg)
|
|
618
|
+
return Element.new(self, element_id) if element_id
|
|
619
|
+
|
|
620
|
+
shadow_root_id = shadow_root_id_from(arg)
|
|
621
|
+
return ShadowRoot.new self, shadow_root_id if shadow_root_id
|
|
622
|
+
|
|
623
|
+
arg.each { |k, v| arg[k] = unwrap_script_result(v) }
|
|
624
|
+
else
|
|
625
|
+
arg
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def element_id_from(id)
|
|
630
|
+
id['ELEMENT'] || id[Element::ELEMENT_KEY]
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
def shadow_root_id_from(id)
|
|
634
|
+
id[ShadowRoot::ROOT_KEY]
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
def prepare_capabilities_payload(capabilities)
|
|
638
|
+
capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
|
|
639
|
+
{capabilities: capabilities}
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
def convert_locator(how, what)
|
|
643
|
+
how = SearchContext::FINDERS[how.to_sym] || how
|
|
644
|
+
|
|
645
|
+
case how
|
|
646
|
+
when 'class name'
|
|
647
|
+
how = 'css selector'
|
|
648
|
+
what = ".#{escape_css(what.to_s)}"
|
|
649
|
+
when 'id'
|
|
650
|
+
how = 'css selector'
|
|
651
|
+
what = "##{escape_css(what.to_s)}"
|
|
652
|
+
when 'name'
|
|
653
|
+
how = 'css selector'
|
|
654
|
+
what = "*[name='#{escape_css(what.to_s)}']"
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
if what.is_a?(Hash)
|
|
658
|
+
what = what.each_with_object({}) do |(h, w), hash|
|
|
659
|
+
h, w = convert_locator(h.to_s, w)
|
|
660
|
+
hash[h] = w
|
|
661
|
+
end
|
|
662
|
+
end
|
|
183
663
|
|
|
184
|
-
|
|
185
|
-
desiredCapabilities: oss_capabilities,
|
|
186
|
-
capabilities: {
|
|
187
|
-
firstMatch: [w3c_capabilities]
|
|
188
|
-
}
|
|
189
|
-
}
|
|
664
|
+
[how, what]
|
|
190
665
|
end
|
|
191
666
|
|
|
667
|
+
ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/
|
|
668
|
+
UNICODE_CODE_POINT = 30
|
|
669
|
+
|
|
670
|
+
# Escapes invalid characters in CSS selector.
|
|
671
|
+
# @see https://mathiasbynens.be/notes/css-escapes
|
|
672
|
+
def escape_css(string)
|
|
673
|
+
string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
|
|
674
|
+
string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..]}" if string[0]&.match?(/[[:digit:]]/)
|
|
675
|
+
|
|
676
|
+
string
|
|
677
|
+
end
|
|
192
678
|
end # Bridge
|
|
193
679
|
end # Remote
|
|
194
680
|
end # WebDriver
|