selenium-webdriver 2.45.0 → 3.142.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +795 -3
  3. data/Gemfile +2 -0
  4. data/{COPYING → LICENSE} +1 -3
  5. data/README.md +13 -9
  6. data/lib/selenium/server.rb +93 -71
  7. data/lib/selenium/webdriver/atoms/getAttribute.js +7 -0
  8. data/lib/selenium/webdriver/atoms/isDisplayed.js +102 -0
  9. data/lib/selenium/webdriver/atoms.rb +37 -0
  10. data/lib/selenium/webdriver/chrome/bridge.rb +47 -99
  11. data/lib/selenium/webdriver/chrome/driver.rb +127 -0
  12. data/lib/selenium/webdriver/chrome/options.rb +190 -0
  13. data/lib/selenium/webdriver/chrome/profile.rb +40 -20
  14. data/lib/selenium/webdriver/chrome/service.rb +46 -62
  15. data/lib/selenium/webdriver/chrome.rb +34 -6
  16. data/lib/selenium/webdriver/common/action_builder.rb +69 -56
  17. data/lib/selenium/webdriver/common/alert.rb +25 -8
  18. data/lib/selenium/webdriver/common/bridge_helper.rb +35 -20
  19. data/lib/selenium/webdriver/common/driver.rb +90 -63
  20. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +45 -0
  21. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +50 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +42 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +26 -11
  24. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +51 -0
  25. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +58 -0
  26. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +51 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +23 -6
  28. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +19 -2
  29. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +24 -7
  30. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +19 -3
  31. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +23 -7
  32. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +26 -5
  33. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +20 -6
  34. data/lib/selenium/webdriver/common/element.rb +79 -37
  35. data/lib/selenium/webdriver/common/error.rb +282 -106
  36. data/lib/selenium/webdriver/common/file_reaper.rb +23 -12
  37. data/lib/selenium/webdriver/common/html5/local_storage.rb +29 -12
  38. data/lib/selenium/webdriver/common/html5/session_storage.rb +29 -12
  39. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +29 -18
  40. data/lib/selenium/webdriver/common/interactions/input_device.rb +54 -0
  41. data/lib/selenium/webdriver/common/interactions/interaction.rb +53 -0
  42. data/lib/selenium/webdriver/common/interactions/interactions.rb +43 -0
  43. data/lib/selenium/webdriver/common/interactions/key_actions.rb +145 -0
  44. data/lib/selenium/webdriver/common/interactions/key_input.rb +66 -0
  45. data/lib/selenium/webdriver/common/interactions/none_input.rb +36 -0
  46. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +363 -0
  47. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +139 -0
  48. data/lib/selenium/webdriver/common/keyboard.rb +27 -12
  49. data/lib/selenium/webdriver/common/keys.rb +118 -81
  50. data/lib/selenium/webdriver/common/log_entry.rb +27 -8
  51. data/lib/selenium/webdriver/common/logger.rb +115 -0
  52. data/lib/selenium/webdriver/common/logs.rb +24 -7
  53. data/lib/selenium/webdriver/common/manager.rb +177 -0
  54. data/lib/selenium/webdriver/common/mouse.rb +29 -12
  55. data/lib/selenium/webdriver/common/navigation.rb +21 -4
  56. data/lib/selenium/webdriver/common/options.rb +43 -126
  57. data/lib/selenium/webdriver/common/platform.rb +101 -97
  58. data/lib/selenium/webdriver/common/port_prober.rb +24 -17
  59. data/lib/selenium/webdriver/common/profile_helper.rb +27 -11
  60. data/lib/selenium/webdriver/common/proxy.rb +86 -73
  61. data/lib/selenium/webdriver/common/search_context.rb +49 -33
  62. data/lib/selenium/webdriver/common/service.rb +219 -0
  63. data/lib/selenium/webdriver/common/socket_lock.rb +82 -0
  64. data/lib/selenium/webdriver/common/socket_poller.rb +47 -26
  65. data/lib/selenium/webdriver/common/target_locator.rb +35 -14
  66. data/lib/selenium/webdriver/common/timeouts.rb +23 -6
  67. data/lib/selenium/webdriver/common/touch_action_builder.rb +25 -11
  68. data/lib/selenium/webdriver/common/touch_screen.rb +42 -24
  69. data/lib/selenium/webdriver/common/w3c_action_builder.rb +212 -0
  70. data/lib/selenium/webdriver/common/w3c_manager.rb +45 -0
  71. data/lib/selenium/webdriver/common/wait.rb +34 -14
  72. data/lib/selenium/webdriver/common/window.rb +75 -16
  73. data/lib/selenium/webdriver/common/zipper.rb +26 -11
  74. data/lib/selenium/webdriver/common.rb +40 -7
  75. data/lib/selenium/webdriver/edge/bridge.rb +76 -0
  76. data/lib/selenium/webdriver/edge/driver.rb +66 -0
  77. data/lib/selenium/webdriver/edge/options.rb +80 -0
  78. data/lib/selenium/webdriver/edge/service.rb +52 -0
  79. data/lib/selenium/webdriver/edge.rb +44 -0
  80. data/lib/selenium/webdriver/firefox/binary.rb +70 -48
  81. data/lib/selenium/webdriver/firefox/driver.rb +50 -0
  82. data/lib/selenium/webdriver/firefox/extension/prefs.json +14 -13
  83. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  84. data/lib/selenium/webdriver/firefox/extension.rb +50 -19
  85. data/lib/selenium/webdriver/firefox/launcher.rb +33 -28
  86. data/lib/selenium/webdriver/firefox/legacy/driver.rb +83 -0
  87. data/lib/selenium/webdriver/firefox/marionette/bridge.rb +49 -0
  88. data/lib/selenium/webdriver/firefox/marionette/driver.rb +90 -0
  89. data/lib/selenium/webdriver/firefox/options.rb +162 -0
  90. data/lib/selenium/webdriver/firefox/profile.rb +66 -48
  91. data/lib/selenium/webdriver/firefox/profiles_ini.rb +28 -16
  92. data/lib/selenium/webdriver/firefox/service.rb +52 -0
  93. data/lib/selenium/webdriver/firefox/util.rb +19 -2
  94. data/lib/selenium/webdriver/firefox.rb +46 -10
  95. data/lib/selenium/webdriver/ie/driver.rb +85 -0
  96. data/lib/selenium/webdriver/ie/options.rb +138 -0
  97. data/lib/selenium/webdriver/ie/service.rb +54 -0
  98. data/lib/selenium/webdriver/ie.rb +32 -10
  99. data/lib/selenium/webdriver/remote/bridge.rb +117 -572
  100. data/lib/selenium/webdriver/remote/capabilities.rb +116 -99
  101. data/lib/selenium/webdriver/remote/driver.rb +51 -0
  102. data/lib/selenium/webdriver/remote/http/common.rb +54 -23
  103. data/lib/selenium/webdriver/remote/http/curb.rb +30 -12
  104. data/lib/selenium/webdriver/remote/http/default.rb +85 -42
  105. data/lib/selenium/webdriver/remote/http/persistent.rb +29 -7
  106. data/lib/selenium/webdriver/remote/oss/bridge.rb +594 -0
  107. data/lib/selenium/webdriver/remote/oss/commands.rb +223 -0
  108. data/lib/selenium/webdriver/remote/response.rb +68 -30
  109. data/lib/selenium/webdriver/remote/server_error.rb +22 -5
  110. data/lib/selenium/webdriver/remote/w3c/bridge.rb +605 -0
  111. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +310 -0
  112. data/lib/selenium/webdriver/remote/w3c/commands.rb +157 -0
  113. data/lib/selenium/webdriver/remote.rb +27 -13
  114. data/lib/selenium/webdriver/safari/bridge.rb +38 -107
  115. data/lib/selenium/webdriver/safari/driver.rb +68 -0
  116. data/lib/selenium/webdriver/safari/options.rb +56 -75
  117. data/lib/selenium/webdriver/safari/service.rb +38 -0
  118. data/lib/selenium/webdriver/safari.rb +49 -31
  119. data/lib/selenium/webdriver/support/abstract_event_listener.rb +40 -6
  120. data/lib/selenium/webdriver/support/block_event_listener.rb +24 -7
  121. data/lib/selenium/webdriver/support/color.rb +82 -46
  122. data/lib/selenium/webdriver/support/escaper.rb +43 -0
  123. data/lib/selenium/webdriver/support/event_firing_bridge.rb +56 -39
  124. data/lib/selenium/webdriver/support/select.rb +66 -89
  125. data/lib/selenium/webdriver/support.rb +20 -0
  126. data/lib/selenium/webdriver/version.rb +24 -0
  127. data/lib/selenium/webdriver.rb +55 -25
  128. data/lib/selenium-webdriver.rb +19 -0
  129. data/selenium-webdriver.gemspec +42 -29
  130. metadata +331 -260
  131. data/Gemfile.lock +0 -48
  132. data/lib/selenium/client/base.rb +0 -132
  133. data/lib/selenium/client/driver.rb +0 -10
  134. data/lib/selenium/client/errors.rb +0 -9
  135. data/lib/selenium/client/extensions.rb +0 -118
  136. data/lib/selenium/client/idiomatic.rb +0 -488
  137. data/lib/selenium/client/javascript_expression_builder.rb +0 -116
  138. data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -13
  139. data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -13
  140. data/lib/selenium/client/legacy_driver.rb +0 -1720
  141. data/lib/selenium/client/protocol.rb +0 -104
  142. data/lib/selenium/client/selenium_helper.rb +0 -34
  143. data/lib/selenium/client.rb +0 -38
  144. data/lib/selenium/rake/server_task.rb +0 -157
  145. data/lib/selenium/webdriver/android/bridge.rb +0 -49
  146. data/lib/selenium/webdriver/android.rb +0 -9
  147. data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -9
  148. data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -42
  149. data/lib/selenium/webdriver/common/core_ext/string.rb +0 -5
  150. data/lib/selenium/webdriver/common/driver_extensions/has_browser_connection.rb +0 -17
  151. data/lib/selenium/webdriver/common/driver_extensions/has_input_devices.rb +0 -39
  152. data/lib/selenium/webdriver/common/html5/location.rb +0 -0
  153. data/lib/selenium/webdriver/common/json_helper.rb +0 -34
  154. data/lib/selenium/webdriver/firefox/bridge.rb +0 -70
  155. data/lib/selenium/webdriver/firefox/socket_lock.rb +0 -61
  156. data/lib/selenium/webdriver/ie/bridge.rb +0 -69
  157. data/lib/selenium/webdriver/ie/server.rb +0 -90
  158. data/lib/selenium/webdriver/iphone/bridge.rb +0 -45
  159. data/lib/selenium/webdriver/iphone.rb +0 -9
  160. data/lib/selenium/webdriver/opera/bridge.rb +0 -112
  161. data/lib/selenium/webdriver/opera/service.rb +0 -49
  162. data/lib/selenium/webdriver/opera.rb +0 -24
  163. data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -59
  164. data/lib/selenium/webdriver/phantomjs/service.rb +0 -90
  165. data/lib/selenium/webdriver/phantomjs.rb +0 -22
  166. data/lib/selenium/webdriver/remote/commands.rb +0 -192
  167. data/lib/selenium/webdriver/safari/browser.rb +0 -20
  168. data/lib/selenium/webdriver/safari/extensions.rb +0 -170
  169. data/lib/selenium/webdriver/safari/resources/SafariDriver.safariextz +0 -0
  170. data/lib/selenium/webdriver/safari/resources/client.js +0 -6903
  171. data/lib/selenium/webdriver/safari/server.rb +0 -145
  172. 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
- # Defines a wrapper method for a command, which ultimately calls #execute.
18
- #
19
- # @param name [Symbol]
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
- # Initializes the bridge with the given server URL.
36
+ # Implements protocol handshake which:
37
37
  #
38
- # @param url [String] url for the remote server
39
- # @param http_client [Object] an HTTP client instance that implements the same protocol as Http::Default
40
- # @param desired_capabilities [Capabilities] an instance of Remote::Capabilities describing the capabilities you want
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
- def initialize(opts = {})
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.send(desired_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
- execute :sendKeysToElement, {:id => element}, {:value => Array(keys)}
418
- end
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
- def touchUp(x, y)
458
- execute :touchUp, {}, :x => x, :y => y
459
- end
460
-
461
- def touchMove(x, y)
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
- execute :touchScroll, {}, :xoffset => x, :yoffset => y
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
- # logs
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 getAvailableLogTypes
500
- types = execute :getAvailableLogTypes
501
- Array(types).map { |e| e.to_sym }
502
- end
77
+ def initialize(opts = {})
78
+ opts = opts.dup
503
79
 
504
- def getLog(type)
505
- data = execute :getLog, {}, :type => type.to_s
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
- Array(data).map do |l|
508
- LogEntry.new l.fetch('level'), l.fetch('timestamp'), l.fetch('message')
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
- def getElementValue(element)
525
- execute :getElementValue, :id => element
526
- end
88
+ uri = url.is_a?(URI) ? url : URI.parse(url)
89
+ uri.path += '/' unless uri.path =~ %r{\/$}
527
90
 
528
- def getElementText(element)
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
- Point.new data['x'], data['y']
93
+ @http = http_client
94
+ @file_detector = nil
536
95
  end
537
96
 
538
- def getElementLocationOnceScrolledIntoView(element)
539
- data = execute :getElementLocationOnceScrolledIntoView, :id => element
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 getElementSize(element)
545
- data = execute :getElementSize, :id => element
101
+ def create_session(desired_capabilities, options = nil)
102
+ response = execute(:new_session, {}, merged_capabilities(desired_capabilities, options))
546
103
 
547
- Dimension.new data['width'], data['height']
548
- end
104
+ @session_id = response['sessionId']
105
+ oss_status = response['status']
106
+ value = response['value']
549
107
 
550
- def isElementEnabled(element)
551
- execute :isElementEnabled, :id => element
552
- end
108
+ if value.is_a?(Hash)
109
+ @session_id = value['sessionId'] if value.key?('sessionId')
553
110
 
554
- def isElementSelected(element)
555
- execute :isElementSelected, :id => element
556
- end
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
- def isElementDisplayed(element)
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
- def elementEquals(element, other)
566
- if element.ref == other.ref
567
- true
120
+ if oss_status
121
+ WebDriver.logger.info 'Detected OSS dialect.'
122
+ @dialect = :oss
123
+ Capabilities.json_create(value)
568
124
  else
569
- execute :elementEquals, :id => element.ref, :other => other.ref
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
- # finding elements
132
+ # Returns the current session ID.
575
133
  #
576
134
 
577
- def getActiveElement
578
- Element.new self, element_id_from(execute(:getActiveElement))
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 find_elements_by(how, what, parent = nil)
593
- if parent
594
- ids = execute :findChildElements, {:id => parent}, {:using => how, :value => what}
595
- else
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 raw_execute(command, opts = {}, command_hash = nil)
628
- verb, path = COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
629
- path = path.dup
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'] = @session_id if path.include?(":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
- puts "-> #{verb.to_s.upcase} #{path}" if $DEBUG
640
- http.call verb, path, command_hash
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::Parser.new : 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