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