selenium-webdriver 2.53.3 → 3.142.7
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 +7 -0
- data/CHANGES +665 -8
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/README.md +2 -3
- data/lib/selenium/server.rb +76 -73
- data/lib/selenium/webdriver/atoms/getAttribute.js +7 -0
- data/lib/selenium/webdriver/atoms/isDisplayed.js +102 -0
- data/lib/selenium/webdriver/{phantomjs.rb → atoms.rb} +10 -14
- data/lib/selenium/webdriver/chrome/bridge.rb +30 -101
- data/lib/selenium/webdriver/chrome/driver.rb +127 -0
- data/lib/selenium/webdriver/chrome/options.rb +190 -0
- data/lib/selenium/webdriver/chrome/profile.rb +21 -20
- data/lib/selenium/webdriver/chrome/service.rb +26 -93
- data/lib/selenium/webdriver/chrome.rb +15 -6
- data/lib/selenium/webdriver/common/action_builder.rb +52 -58
- data/lib/selenium/webdriver/common/alert.rb +7 -15
- data/lib/selenium/webdriver/common/bridge_helper.rb +18 -22
- data/lib/selenium/webdriver/common/driver.rb +72 -72
- data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +45 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +50 -0
- data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_debugger.rb} +11 -27
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +6 -10
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +7 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +2 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +2 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +3 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +2 -5
- data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +6 -9
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +9 -7
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +3 -8
- data/lib/selenium/webdriver/common/element.rb +59 -39
- data/lib/selenium/webdriver/common/error.rb +259 -104
- data/lib/selenium/webdriver/common/file_reaper.rb +6 -14
- data/lib/selenium/webdriver/common/html5/local_storage.rb +8 -10
- data/lib/selenium/webdriver/common/html5/session_storage.rb +8 -10
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +8 -16
- data/lib/selenium/webdriver/common/interactions/input_device.rb +54 -0
- data/lib/selenium/webdriver/common/interactions/interaction.rb +53 -0
- data/lib/selenium/webdriver/{safari/browser.rb → common/interactions/interactions.rb} +17 -14
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +145 -0
- data/lib/selenium/webdriver/common/interactions/key_input.rb +66 -0
- data/lib/selenium/webdriver/{android.rb → common/interactions/none_input.rb} +14 -6
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +363 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +139 -0
- data/lib/selenium/webdriver/common/keyboard.rb +10 -14
- data/lib/selenium/webdriver/common/keys.rb +102 -82
- data/lib/selenium/webdriver/common/log_entry.rb +7 -8
- data/lib/selenium/webdriver/common/logger.rb +115 -0
- data/lib/selenium/webdriver/common/logs.rb +4 -6
- data/lib/selenium/webdriver/common/manager.rb +177 -0
- data/lib/selenium/webdriver/common/mouse.rb +12 -14
- data/lib/selenium/webdriver/common/navigation.rb +4 -6
- data/lib/selenium/webdriver/common/options.rb +26 -127
- data/lib/selenium/webdriver/common/platform.rb +75 -101
- data/lib/selenium/webdriver/common/port_prober.rb +7 -19
- data/lib/selenium/webdriver/common/profile_helper.rb +8 -11
- data/lib/selenium/webdriver/common/proxy.rb +68 -74
- data/lib/selenium/webdriver/common/search_context.rb +28 -37
- data/lib/selenium/webdriver/common/service.rb +219 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +15 -16
- data/lib/selenium/webdriver/common/socket_poller.rb +30 -28
- data/lib/selenium/webdriver/common/target_locator.rb +16 -18
- data/lib/selenium/webdriver/common/timeouts.rb +6 -8
- data/lib/selenium/webdriver/common/touch_action_builder.rb +5 -10
- data/lib/selenium/webdriver/common/touch_screen.rb +22 -23
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +212 -0
- data/lib/selenium/webdriver/common/w3c_manager.rb +45 -0
- data/lib/selenium/webdriver/common/wait.rb +17 -16
- data/lib/selenium/webdriver/common/window.rb +50 -17
- data/lib/selenium/webdriver/common/zipper.rb +9 -13
- data/lib/selenium/webdriver/common.rb +21 -7
- data/lib/selenium/webdriver/edge/bridge.rb +34 -63
- data/lib/selenium/webdriver/edge/driver.rb +66 -0
- data/lib/selenium/webdriver/edge/options.rb +80 -0
- data/lib/selenium/webdriver/edge/service.rb +23 -95
- data/lib/selenium/webdriver/edge.rb +13 -13
- data/lib/selenium/webdriver/firefox/binary.rb +45 -60
- data/lib/selenium/webdriver/firefox/driver.rb +50 -0
- data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -12
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/extension.rb +20 -10
- data/lib/selenium/webdriver/firefox/launcher.rb +16 -22
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +83 -0
- data/lib/selenium/webdriver/firefox/marionette/bridge.rb +49 -0
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +90 -0
- data/lib/selenium/webdriver/firefox/options.rb +162 -0
- data/lib/selenium/webdriver/firefox/profile.rb +47 -48
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +11 -18
- data/lib/selenium/webdriver/firefox/service.rb +24 -95
- data/lib/selenium/webdriver/firefox/util.rb +2 -4
- data/lib/selenium/webdriver/firefox.rb +27 -12
- data/lib/selenium/webdriver/ie/driver.rb +85 -0
- data/lib/selenium/webdriver/ie/options.rb +138 -0
- data/lib/selenium/webdriver/ie/service.rb +54 -0
- data/lib/selenium/webdriver/ie.rb +12 -10
- data/lib/selenium/webdriver/remote/bridge.rb +100 -564
- data/lib/selenium/webdriver/remote/capabilities.rb +98 -100
- data/lib/selenium/webdriver/remote/driver.rb +51 -0
- data/lib/selenium/webdriver/remote/http/common.rb +34 -22
- data/lib/selenium/webdriver/remote/http/curb.rb +13 -14
- data/lib/selenium/webdriver/remote/http/default.rb +62 -43
- data/lib/selenium/webdriver/remote/http/persistent.rb +12 -9
- data/lib/selenium/webdriver/remote/oss/bridge.rb +594 -0
- data/lib/selenium/webdriver/remote/oss/commands.rb +223 -0
- data/lib/selenium/webdriver/remote/response.rb +48 -28
- data/lib/selenium/webdriver/remote/server_error.rb +3 -5
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +605 -0
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +310 -0
- data/lib/selenium/webdriver/remote/w3c/commands.rb +157 -0
- data/lib/selenium/webdriver/remote.rb +10 -16
- data/lib/selenium/webdriver/safari/bridge.rb +17 -101
- data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +27 -25
- data/lib/selenium/webdriver/safari/options.rb +29 -31
- data/lib/selenium/webdriver/safari/service.rb +38 -0
- data/lib/selenium/webdriver/safari.rb +27 -27
- data/lib/selenium/webdriver/support/abstract_event_listener.rb +19 -4
- data/lib/selenium/webdriver/support/block_event_listener.rb +3 -5
- data/lib/selenium/webdriver/support/color.rb +60 -43
- data/lib/selenium/webdriver/support/escaper.rb +43 -0
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +39 -41
- data/lib/selenium/webdriver/support/select.rb +45 -97
- data/lib/selenium/webdriver/support.rb +3 -2
- data/lib/selenium/webdriver/{iphone.rb → version.rb} +3 -7
- data/lib/selenium/webdriver.rb +36 -23
- data/lib/selenium-webdriver.rb +2 -2
- data/selenium-webdriver.gemspec +42 -29
- metadata +331 -262
- data/lib/selenium/client/base.rb +0 -151
- data/lib/selenium/client/driver.rb +0 -29
- data/lib/selenium/client/errors.rb +0 -28
- data/lib/selenium/client/extensions.rb +0 -132
- data/lib/selenium/client/idiomatic.rb +0 -507
- data/lib/selenium/client/javascript_expression_builder.rb +0 -135
- data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
- data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
- data/lib/selenium/client/legacy_driver.rb +0 -1722
- data/lib/selenium/client/protocol.rb +0 -123
- data/lib/selenium/client/selenium_helper.rb +0 -49
- data/lib/selenium/client.rb +0 -57
- data/lib/selenium/rake/server_task.rb +0 -176
- data/lib/selenium/webdriver/android/bridge.rb +0 -68
- data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
- data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
- data/lib/selenium/webdriver/common/html5/location.rb +0 -19
- data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
- data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
- data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
- data/lib/selenium/webdriver/ie/bridge.rb +0 -88
- data/lib/selenium/webdriver/ie/server.rb +0 -133
- data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
- data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
- data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
- data/lib/selenium/webdriver/remote/commands.rb +0 -211
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
- data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
- data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
- data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
- data/lib/selenium/webdriver/safari/server.rb +0 -187
- data/lib/selenium-client.rb +0 -21
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -20,624 +20,142 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Remote
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
# Low level bridge to the remote server, through which the rest of the API works.
|
|
26
|
-
#
|
|
27
|
-
# @api private
|
|
28
|
-
#
|
|
29
|
-
|
|
30
23
|
class Bridge
|
|
24
|
+
include Atoms
|
|
31
25
|
include BridgeHelper
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
# @param name [Symbol]
|
|
39
|
-
# name of the resulting method
|
|
40
|
-
# @param url [String]
|
|
41
|
-
# a URL template, which can include some arguments, much like the definitions on the server.
|
|
42
|
-
# the :session_id parameter is implicitly handled, but the remainder will become required method arguments.
|
|
43
|
-
# @param verb [Symbol]
|
|
44
|
-
# the appropriate http verb, such as :get, :post, or :delete
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
def self.command(name, verb, url)
|
|
48
|
-
COMMANDS[name] = [verb, url.freeze]
|
|
49
|
-
end
|
|
27
|
+
PORT = 4444
|
|
28
|
+
COMMANDS = {
|
|
29
|
+
new_session: [:post, 'session']
|
|
30
|
+
}.freeze
|
|
50
31
|
|
|
51
32
|
attr_accessor :context, :http, :file_detector
|
|
52
|
-
attr_reader :capabilities
|
|
33
|
+
attr_reader :capabilities, :dialect
|
|
53
34
|
|
|
54
35
|
#
|
|
55
|
-
#
|
|
36
|
+
# Implements protocol handshake which:
|
|
56
37
|
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
38
|
+
# 1. Creates session with driver.
|
|
39
|
+
# 2. Sniffs response.
|
|
40
|
+
# 3. Based on the response, understands which dialect we should use.
|
|
60
41
|
#
|
|
42
|
+
# @return [OSS:Bridge, W3C::Bridge]
|
|
43
|
+
#
|
|
44
|
+
def self.handshake(**opts)
|
|
45
|
+
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
opts = opts.dup
|
|
64
|
-
|
|
65
|
-
http_client = opts.delete(:http_client) { Http::Default.new }
|
|
66
|
-
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.firefox }
|
|
67
|
-
url = opts.delete(:url) { "http://#{Platform.localhost}:4444/wd/hub" }
|
|
68
|
-
|
|
69
|
-
unless opts.empty?
|
|
70
|
-
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
if desired_capabilities.kind_of?(Symbol)
|
|
47
|
+
if desired_capabilities.is_a?(Symbol)
|
|
74
48
|
unless Capabilities.respond_to?(desired_capabilities)
|
|
75
49
|
raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
|
|
76
50
|
end
|
|
77
51
|
|
|
78
|
-
desired_capabilities = Capabilities.
|
|
52
|
+
desired_capabilities = Capabilities.__send__(desired_capabilities)
|
|
79
53
|
end
|
|
80
54
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
http_client.server_url = uri
|
|
85
|
-
|
|
86
|
-
@http = http_client
|
|
87
|
-
@capabilities = create_session(desired_capabilities)
|
|
88
|
-
|
|
89
|
-
@file_detector = nil
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def browser
|
|
93
|
-
@browser ||= (
|
|
94
|
-
name = @capabilities.browser_name
|
|
95
|
-
name ? name.gsub(" ", "_").to_sym : 'unknown'
|
|
96
|
-
)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def driver_extensions
|
|
100
|
-
[
|
|
101
|
-
DriverExtensions::HasInputDevices,
|
|
102
|
-
DriverExtensions::UploadsFiles,
|
|
103
|
-
DriverExtensions::TakesScreenshot,
|
|
104
|
-
DriverExtensions::HasSessionId,
|
|
105
|
-
DriverExtensions::Rotatable,
|
|
106
|
-
DriverExtensions::HasTouchScreen,
|
|
107
|
-
DriverExtensions::HasLocation,
|
|
108
|
-
DriverExtensions::HasNetworkConnection,
|
|
109
|
-
DriverExtensions::HasRemoteStatus,
|
|
110
|
-
DriverExtensions::HasWebStorage
|
|
111
|
-
]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
#
|
|
115
|
-
# Returns the current session ID.
|
|
116
|
-
#
|
|
117
|
-
|
|
118
|
-
def session_id
|
|
119
|
-
@session_id || raise(Error::WebDriverError, "no current session exists")
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def create_session(desired_capabilities)
|
|
123
|
-
resp = raw_execute :newSession, {}, :desiredCapabilities => desired_capabilities
|
|
124
|
-
@session_id = resp['sessionId'] or raise Error::WebDriverError, 'no sessionId in returned payload'
|
|
125
|
-
|
|
126
|
-
Capabilities.json_create resp['value']
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def status
|
|
130
|
-
execute :status
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def get(url)
|
|
134
|
-
execute :get, {}, :url => url
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def getCapabilities
|
|
138
|
-
Capabilities.json_create execute(:getCapabilities)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def setImplicitWaitTimeout(milliseconds)
|
|
142
|
-
execute :implicitlyWait, {}, :ms => milliseconds
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def setScriptTimeout(milliseconds)
|
|
146
|
-
execute :setScriptTimeout, {}, :ms => milliseconds
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def setTimeout(type, milliseconds)
|
|
150
|
-
execute :setTimeout, {}, :type => type, :ms => milliseconds
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
#
|
|
154
|
-
# alerts
|
|
155
|
-
#
|
|
156
|
-
|
|
157
|
-
def acceptAlert
|
|
158
|
-
execute :acceptAlert
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def dismissAlert
|
|
162
|
-
execute :dismissAlert
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def setAlertValue(keys)
|
|
166
|
-
execute :setAlertValue, {}, :text => keys.to_s
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def getAlertText
|
|
170
|
-
execute :getAlertText
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def setAuthentication(credentials)
|
|
174
|
-
execute :setAuthentication, {}, credentials
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
#
|
|
178
|
-
# navigation
|
|
179
|
-
#
|
|
180
|
-
|
|
181
|
-
def goBack
|
|
182
|
-
execute :goBack
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def goForward
|
|
186
|
-
execute :goForward
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def getCurrentUrl
|
|
190
|
-
execute :getCurrentUrl
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def getTitle
|
|
194
|
-
execute :getTitle
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def getPageSource
|
|
198
|
-
execute :getPageSource
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def switchToWindow(name)
|
|
202
|
-
execute :switchToWindow, {}, :name => name
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def switchToFrame(id)
|
|
206
|
-
execute :switchToFrame, {}, :id => id
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def switchToParentFrame
|
|
210
|
-
execute :switchToParentFrame
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def switchToDefaultContent
|
|
214
|
-
execute :switchToFrame, {}, :id => nil
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
QUIT_ERRORS = [IOError]
|
|
218
|
-
|
|
219
|
-
def quit
|
|
220
|
-
execute :quit
|
|
221
|
-
http.close
|
|
222
|
-
rescue *QUIT_ERRORS
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def close
|
|
226
|
-
execute :close
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def refresh
|
|
230
|
-
execute :refresh
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
#
|
|
234
|
-
# window handling
|
|
235
|
-
#
|
|
236
|
-
|
|
237
|
-
def getWindowHandles
|
|
238
|
-
execute :getWindowHandles
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def getCurrentWindowHandle
|
|
242
|
-
execute :getCurrentWindowHandle
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def setWindowSize(width, height, handle = :current)
|
|
246
|
-
execute :setWindowSize, {:window_handle => handle},
|
|
247
|
-
:width => width,
|
|
248
|
-
:height => height
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
def maximizeWindow(handle = :current)
|
|
252
|
-
execute :maximizeWindow, :window_handle => handle
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def getWindowSize(handle = :current)
|
|
256
|
-
data = execute :getWindowSize, :window_handle => handle
|
|
257
|
-
|
|
258
|
-
Dimension.new data['width'], data['height']
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
def setWindowPosition(x, y, handle = :current)
|
|
262
|
-
execute :setWindowPosition, {:window_handle => handle},
|
|
263
|
-
:x => x, :y => y
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def getWindowPosition(handle = :current)
|
|
267
|
-
data = execute :getWindowPosition, :window_handle => handle
|
|
268
|
-
|
|
269
|
-
Point.new data['x'], data['y']
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
def getScreenshot
|
|
273
|
-
execute :screenshot
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
#
|
|
277
|
-
# HTML 5
|
|
278
|
-
#
|
|
279
|
-
|
|
280
|
-
def getLocalStorageItem(key)
|
|
281
|
-
execute :getLocalStorageItem, :key => key
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def removeLocalStorageItem(key)
|
|
285
|
-
execute :removeLocalStorageItem, :key => key
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def getLocalStorageKeys
|
|
289
|
-
execute :getLocalStorageKeys
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
def setLocalStorageItem(key, value)
|
|
293
|
-
execute :setLocalStorageItem, {}, :key => key, :value => value
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def clearLocalStorage
|
|
297
|
-
execute :clearLocalStorage
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
def getLocalStorageSize
|
|
301
|
-
execute :getLocalStorageSize
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def getSessionStorageItem(key)
|
|
305
|
-
execute :getSessionStorageItem, :key => key
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def removeSessionStorageItem(key)
|
|
309
|
-
execute :removeSessionStorageItem, :key => key
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
def getSessionStorageKeys
|
|
313
|
-
execute :getSessionStorageKeys
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
def setSessionStorageItem(key, value)
|
|
317
|
-
execute :setSessionStorageItem, {}, :key => key, :value => value
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
def clearSessionStorage
|
|
321
|
-
execute :clearSessionStorage
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
def getSessionStorageSize
|
|
325
|
-
execute :getSessionStorageSize
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
def getLocation
|
|
329
|
-
obj = execute(:getLocation) || {} # android returns null
|
|
330
|
-
Location.new obj['latitude'], obj['longitude'], obj['altitude']
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def setLocation(lat, lon, alt)
|
|
334
|
-
loc = {:latitude => lat, :longitude => lon, :altitude => alt}
|
|
335
|
-
execute :setLocation, {}, :location => loc
|
|
336
|
-
end
|
|
55
|
+
bridge = new(opts)
|
|
56
|
+
capabilities = bridge.create_session(desired_capabilities, opts.delete(:options))
|
|
337
57
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
58
|
+
case bridge.dialect
|
|
59
|
+
when :oss
|
|
60
|
+
Remote::OSS::Bridge.new(capabilities, bridge.session_id, **opts)
|
|
61
|
+
when :w3c
|
|
62
|
+
Remote::W3C::Bridge.new(capabilities, bridge.session_id, **opts)
|
|
63
|
+
else
|
|
64
|
+
raise WebDriverError, 'cannot understand dialect'
|
|
65
|
+
end
|
|
344
66
|
end
|
|
345
67
|
|
|
346
68
|
#
|
|
347
|
-
#
|
|
69
|
+
# Initializes the bridge with the given server URL
|
|
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
|
|
348
75
|
#
|
|
349
76
|
|
|
350
|
-
def
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
result = execute :executeScript, {}, :script => script, :args => args
|
|
354
|
-
unwrap_script_result result
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
def executeAsyncScript(script, *args)
|
|
358
|
-
assert_javascript_enabled
|
|
359
|
-
|
|
360
|
-
result = execute :executeAsyncScript, {}, :script => script, :args => args
|
|
361
|
-
unwrap_script_result result
|
|
362
|
-
end
|
|
77
|
+
def initialize(opts = {})
|
|
78
|
+
opts = opts.dup
|
|
363
79
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
80
|
+
http_client = opts.delete(:http_client) { Http::Default.new }
|
|
81
|
+
url = opts.delete(:url) { "http://#{Platform.localhost}:#{PORT}/wd/hub" }
|
|
82
|
+
opts.delete(:options)
|
|
367
83
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
84
|
+
unless opts.empty?
|
|
85
|
+
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
|
86
|
+
end
|
|
371
87
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
end
|
|
88
|
+
uri = url.is_a?(URI) ? url : URI.parse(url)
|
|
89
|
+
uri.path += '/' unless uri.path =~ %r{\/$}
|
|
375
90
|
|
|
376
|
-
|
|
377
|
-
execute :getCookies
|
|
378
|
-
end
|
|
91
|
+
http_client.server_url = uri
|
|
379
92
|
|
|
380
|
-
|
|
381
|
-
|
|
93
|
+
@http = http_client
|
|
94
|
+
@file_detector = nil
|
|
382
95
|
end
|
|
383
96
|
|
|
384
97
|
#
|
|
385
|
-
#
|
|
98
|
+
# Creates session handling both OSS and W3C dialects.
|
|
386
99
|
#
|
|
387
100
|
|
|
388
|
-
def
|
|
389
|
-
execute
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
def click
|
|
393
|
-
execute :click, {}, :button => 0
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
def doubleClick
|
|
397
|
-
execute :doubleClick
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
def contextClick
|
|
401
|
-
execute :click, {}, :button => 2
|
|
402
|
-
end
|
|
403
|
-
|
|
404
|
-
def mouseDown
|
|
405
|
-
execute :mouseDown
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
def mouseUp
|
|
409
|
-
execute :mouseUp
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
def mouseMoveTo(element, x = nil, y = nil)
|
|
413
|
-
params = { :element => element }
|
|
414
|
-
|
|
415
|
-
if x && y
|
|
416
|
-
params.merge! :xoffset => x, :yoffset => y
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
execute :mouseMoveTo, {}, params
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
def sendKeysToActiveElement(key)
|
|
423
|
-
execute :sendKeysToActiveElement, {}, :value => key
|
|
424
|
-
end
|
|
101
|
+
def create_session(desired_capabilities, options = nil)
|
|
102
|
+
response = execute(:new_session, {}, merged_capabilities(desired_capabilities, options))
|
|
425
103
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
end
|
|
104
|
+
@session_id = response['sessionId']
|
|
105
|
+
oss_status = response['status']
|
|
106
|
+
value = response['value']
|
|
430
107
|
|
|
431
|
-
|
|
432
|
-
|
|
108
|
+
if value.is_a?(Hash)
|
|
109
|
+
@session_id = value['sessionId'] if value.key?('sessionId')
|
|
433
110
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
111
|
+
if value.key?('capabilities')
|
|
112
|
+
value = value['capabilities']
|
|
113
|
+
elsif value.key?('value')
|
|
114
|
+
value = value['value']
|
|
115
|
+
end
|
|
437
116
|
end
|
|
438
117
|
|
|
439
|
-
|
|
440
|
-
end
|
|
118
|
+
raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
|
|
441
119
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
def submitElement(element)
|
|
447
|
-
execute :submitElement, :id => element
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
def dragElement(element, right_by, down_by)
|
|
451
|
-
execute :dragElement, {:id => element}, :x => right_by, :y => down_by
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
def touchSingleTap(element)
|
|
455
|
-
execute :touchSingleTap, {}, :element => element
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
def touchDoubleTap(element)
|
|
459
|
-
execute :touchDoubleTap, {}, :element => element
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
def touchLongPress(element)
|
|
463
|
-
execute :touchLongPress, {}, :element => element
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
def touchDown(x, y)
|
|
467
|
-
execute :touchDown, {}, :x => x, :y => y
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
def touchUp(x, y)
|
|
471
|
-
execute :touchUp, {}, :x => x, :y => y
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
def touchMove(x, y)
|
|
475
|
-
execute :touchMove, {}, :x => x, :y => y
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
def touchScroll(element, x, y)
|
|
479
|
-
if element
|
|
480
|
-
execute :touchScroll, {}, :element => element,
|
|
481
|
-
:xoffset => x,
|
|
482
|
-
:yoffset => y
|
|
120
|
+
if oss_status
|
|
121
|
+
WebDriver.logger.info 'Detected OSS dialect.'
|
|
122
|
+
@dialect = :oss
|
|
123
|
+
Capabilities.json_create(value)
|
|
483
124
|
else
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
def touchFlick(xspeed, yspeed)
|
|
489
|
-
execute :touchFlick, {}, :xspeed => xspeed, :yspeed => yspeed
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
def touchElementFlick(element, right_by, down_by, speed)
|
|
493
|
-
execute :touchFlick, {}, :element => element,
|
|
494
|
-
:xoffset => right_by,
|
|
495
|
-
:yoffset => down_by,
|
|
496
|
-
:speed => speed
|
|
497
|
-
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
def setScreenOrientation(orientation)
|
|
501
|
-
execute :setScreenOrientation, {}, :orientation => orientation
|
|
502
|
-
end
|
|
503
|
-
|
|
504
|
-
def getScreenOrientation
|
|
505
|
-
execute :getScreenOrientation
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
#
|
|
509
|
-
# logs
|
|
510
|
-
#
|
|
511
|
-
|
|
512
|
-
def getAvailableLogTypes
|
|
513
|
-
types = execute :getAvailableLogTypes
|
|
514
|
-
Array(types).map { |e| e.to_sym }
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
def getLog(type)
|
|
518
|
-
data = execute :getLog, {}, :type => type.to_s
|
|
519
|
-
|
|
520
|
-
Array(data).map do |l|
|
|
521
|
-
begin
|
|
522
|
-
LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
|
|
523
|
-
rescue KeyError
|
|
524
|
-
next
|
|
525
|
-
end
|
|
125
|
+
WebDriver.logger.info 'Detected W3C dialect.'
|
|
126
|
+
@dialect = :w3c
|
|
127
|
+
W3C::Capabilities.json_create(value)
|
|
526
128
|
end
|
|
527
129
|
end
|
|
528
130
|
|
|
529
131
|
#
|
|
530
|
-
#
|
|
531
|
-
#
|
|
532
|
-
|
|
533
|
-
def getElementTagName(element)
|
|
534
|
-
execute :getElementTagName, :id => element
|
|
535
|
-
end
|
|
536
|
-
|
|
537
|
-
def getElementAttribute(element, name)
|
|
538
|
-
execute :getElementAttribute, :id => element, :name => name
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
def getElementValue(element)
|
|
542
|
-
execute :getElementValue, :id => element
|
|
543
|
-
end
|
|
544
|
-
|
|
545
|
-
def getElementText(element)
|
|
546
|
-
execute :getElementText, :id => element
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
def getElementLocation(element)
|
|
550
|
-
data = execute :getElementLocation, :id => element
|
|
551
|
-
|
|
552
|
-
Point.new data['x'], data['y']
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def getElementLocationOnceScrolledIntoView(element)
|
|
556
|
-
data = execute :getElementLocationOnceScrolledIntoView, :id => element
|
|
557
|
-
|
|
558
|
-
Point.new data['x'], data['y']
|
|
559
|
-
end
|
|
560
|
-
|
|
561
|
-
def getElementSize(element)
|
|
562
|
-
data = execute :getElementSize, :id => element
|
|
563
|
-
|
|
564
|
-
Dimension.new data['width'], data['height']
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
def isElementEnabled(element)
|
|
568
|
-
execute :isElementEnabled, :id => element
|
|
569
|
-
end
|
|
570
|
-
|
|
571
|
-
def isElementSelected(element)
|
|
572
|
-
execute :isElementSelected, :id => element
|
|
573
|
-
end
|
|
574
|
-
|
|
575
|
-
def isElementDisplayed(element)
|
|
576
|
-
execute :isElementDisplayed, :id => element
|
|
577
|
-
end
|
|
578
|
-
|
|
579
|
-
def getElementValueOfCssProperty(element, prop)
|
|
580
|
-
execute :getElementValueOfCssProperty, :id => element, :property_name => prop
|
|
581
|
-
end
|
|
582
|
-
|
|
583
|
-
#
|
|
584
|
-
# finding elements
|
|
132
|
+
# Returns the current session ID.
|
|
585
133
|
#
|
|
586
134
|
|
|
587
|
-
def
|
|
588
|
-
|
|
135
|
+
def session_id
|
|
136
|
+
@session_id || raise(Error::WebDriverError, 'no current session exists')
|
|
589
137
|
end
|
|
590
|
-
alias_method :switchToActiveElement, :getActiveElement
|
|
591
138
|
|
|
592
|
-
def
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
id = execute :findElement, {}, {:using => how, :value => what}
|
|
139
|
+
def browser
|
|
140
|
+
@browser ||= begin
|
|
141
|
+
name = @capabilities.browser_name
|
|
142
|
+
name ? name.tr(' ', '_').to_sym : 'unknown'
|
|
597
143
|
end
|
|
598
|
-
|
|
599
|
-
Element.new self, element_id_from(id)
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
def find_elements_by(how, what, parent = nil)
|
|
603
|
-
if parent
|
|
604
|
-
ids = execute :findChildElements, {:id => parent}, {:using => how, :value => what}
|
|
605
|
-
else
|
|
606
|
-
ids = execute :findElements, {}, {:using => how, :value => what}
|
|
607
|
-
end
|
|
608
|
-
|
|
609
|
-
ids.map { |id| Element.new self, element_id_from(id) }
|
|
610
144
|
end
|
|
611
145
|
|
|
612
146
|
private
|
|
613
147
|
|
|
614
|
-
def assert_javascript_enabled
|
|
615
|
-
return if capabilities.javascript_enabled?
|
|
616
|
-
raise Error::UnsupportedOperationError, "underlying webdriver instance does not support javascript"
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
#
|
|
620
|
-
# executes a command on the remote server.
|
|
621
|
-
#
|
|
622
|
-
#
|
|
623
|
-
# Returns the 'value' of the returned payload
|
|
624
|
-
#
|
|
625
|
-
|
|
626
|
-
def execute(*args)
|
|
627
|
-
raw_execute(*args)['value']
|
|
628
|
-
end
|
|
629
|
-
|
|
630
148
|
#
|
|
631
149
|
# executes a command on the remote server.
|
|
632
150
|
#
|
|
633
151
|
# @return [WebDriver::Remote::Response]
|
|
634
152
|
#
|
|
635
153
|
|
|
636
|
-
def
|
|
637
|
-
verb, path =
|
|
638
|
-
path
|
|
154
|
+
def execute(command, opts = {}, command_hash = nil)
|
|
155
|
+
verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
|
|
156
|
+
path = path.dup
|
|
639
157
|
|
|
640
|
-
path[':session_id'] =
|
|
158
|
+
path[':session_id'] = session_id if path.include?(':session_id')
|
|
641
159
|
|
|
642
160
|
begin
|
|
643
161
|
opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
|
|
@@ -645,12 +163,30 @@ module Selenium
|
|
|
645
163
|
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
|
646
164
|
end
|
|
647
165
|
|
|
648
|
-
|
|
649
|
-
http.call
|
|
166
|
+
WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
|
|
167
|
+
http.call(verb, path, command_hash)
|
|
650
168
|
end
|
|
651
169
|
|
|
652
170
|
def escaper
|
|
653
|
-
@escaper ||= defined?(URI::Parser) ? URI::
|
|
171
|
+
@escaper ||= defined?(URI::Parser) ? URI::DEFAULT_PARSER : URI
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def commands(command)
|
|
175
|
+
raise NotImplementedError unless command == :new_session
|
|
176
|
+
|
|
177
|
+
COMMANDS[command]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def merged_capabilities(oss_capabilities, options = nil)
|
|
181
|
+
w3c_capabilities = W3C::Capabilities.from_oss(oss_capabilities)
|
|
182
|
+
w3c_capabilities.merge!(options.as_json) if options
|
|
183
|
+
|
|
184
|
+
{
|
|
185
|
+
desiredCapabilities: oss_capabilities,
|
|
186
|
+
capabilities: {
|
|
187
|
+
firstMatch: [w3c_capabilities]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
654
190
|
end
|
|
655
191
|
|
|
656
192
|
end # Bridge
|