selenium-webdriver 2.53.3 → 3.142.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +665 -8
  3. data/Gemfile +2 -0
  4. data/LICENSE +1 -1
  5. data/README.md +2 -3
  6. data/lib/selenium/server.rb +76 -73
  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/{phantomjs.rb → atoms.rb} +10 -14
  10. data/lib/selenium/webdriver/chrome/bridge.rb +30 -101
  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 +21 -20
  14. data/lib/selenium/webdriver/chrome/service.rb +26 -93
  15. data/lib/selenium/webdriver/chrome.rb +15 -6
  16. data/lib/selenium/webdriver/common/action_builder.rb +52 -58
  17. data/lib/selenium/webdriver/common/alert.rb +7 -15
  18. data/lib/selenium/webdriver/common/bridge_helper.rb +18 -22
  19. data/lib/selenium/webdriver/common/driver.rb +72 -72
  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_input_devices.rb → has_debugger.rb} +11 -27
  23. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +6 -10
  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 +7 -8
  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 +2 -4
  28. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +2 -4
  29. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +3 -5
  30. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +2 -5
  31. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +6 -9
  32. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +9 -7
  33. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +3 -8
  34. data/lib/selenium/webdriver/common/element.rb +59 -39
  35. data/lib/selenium/webdriver/common/error.rb +259 -104
  36. data/lib/selenium/webdriver/common/file_reaper.rb +6 -14
  37. data/lib/selenium/webdriver/common/html5/local_storage.rb +8 -10
  38. data/lib/selenium/webdriver/common/html5/session_storage.rb +8 -10
  39. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +8 -16
  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/{safari/browser.rb → common/interactions/interactions.rb} +17 -14
  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/{android.rb → common/interactions/none_input.rb} +14 -6
  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 +10 -14
  49. data/lib/selenium/webdriver/common/keys.rb +102 -82
  50. data/lib/selenium/webdriver/common/log_entry.rb +7 -8
  51. data/lib/selenium/webdriver/common/logger.rb +115 -0
  52. data/lib/selenium/webdriver/common/logs.rb +4 -6
  53. data/lib/selenium/webdriver/common/manager.rb +177 -0
  54. data/lib/selenium/webdriver/common/mouse.rb +12 -14
  55. data/lib/selenium/webdriver/common/navigation.rb +4 -6
  56. data/lib/selenium/webdriver/common/options.rb +26 -127
  57. data/lib/selenium/webdriver/common/platform.rb +75 -101
  58. data/lib/selenium/webdriver/common/port_prober.rb +7 -19
  59. data/lib/selenium/webdriver/common/profile_helper.rb +8 -11
  60. data/lib/selenium/webdriver/common/proxy.rb +68 -74
  61. data/lib/selenium/webdriver/common/search_context.rb +28 -37
  62. data/lib/selenium/webdriver/common/service.rb +219 -0
  63. data/lib/selenium/webdriver/common/socket_lock.rb +15 -16
  64. data/lib/selenium/webdriver/common/socket_poller.rb +30 -28
  65. data/lib/selenium/webdriver/common/target_locator.rb +16 -18
  66. data/lib/selenium/webdriver/common/timeouts.rb +6 -8
  67. data/lib/selenium/webdriver/common/touch_action_builder.rb +5 -10
  68. data/lib/selenium/webdriver/common/touch_screen.rb +22 -23
  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 +17 -16
  72. data/lib/selenium/webdriver/common/window.rb +50 -17
  73. data/lib/selenium/webdriver/common/zipper.rb +9 -13
  74. data/lib/selenium/webdriver/common.rb +21 -7
  75. data/lib/selenium/webdriver/edge/bridge.rb +34 -63
  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 +23 -95
  79. data/lib/selenium/webdriver/edge.rb +13 -13
  80. data/lib/selenium/webdriver/firefox/binary.rb +45 -60
  81. data/lib/selenium/webdriver/firefox/driver.rb +50 -0
  82. data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -12
  83. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  84. data/lib/selenium/webdriver/firefox/extension.rb +20 -10
  85. data/lib/selenium/webdriver/firefox/launcher.rb +16 -22
  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 +47 -48
  91. data/lib/selenium/webdriver/firefox/profiles_ini.rb +11 -18
  92. data/lib/selenium/webdriver/firefox/service.rb +24 -95
  93. data/lib/selenium/webdriver/firefox/util.rb +2 -4
  94. data/lib/selenium/webdriver/firefox.rb +27 -12
  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 +12 -10
  99. data/lib/selenium/webdriver/remote/bridge.rb +100 -564
  100. data/lib/selenium/webdriver/remote/capabilities.rb +98 -100
  101. data/lib/selenium/webdriver/remote/driver.rb +51 -0
  102. data/lib/selenium/webdriver/remote/http/common.rb +34 -22
  103. data/lib/selenium/webdriver/remote/http/curb.rb +13 -14
  104. data/lib/selenium/webdriver/remote/http/default.rb +62 -43
  105. data/lib/selenium/webdriver/remote/http/persistent.rb +12 -9
  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 +48 -28
  109. data/lib/selenium/webdriver/remote/server_error.rb +3 -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 +10 -16
  114. data/lib/selenium/webdriver/safari/bridge.rb +17 -101
  115. data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +27 -25
  116. data/lib/selenium/webdriver/safari/options.rb +29 -31
  117. data/lib/selenium/webdriver/safari/service.rb +38 -0
  118. data/lib/selenium/webdriver/safari.rb +27 -27
  119. data/lib/selenium/webdriver/support/abstract_event_listener.rb +19 -4
  120. data/lib/selenium/webdriver/support/block_event_listener.rb +3 -5
  121. data/lib/selenium/webdriver/support/color.rb +60 -43
  122. data/lib/selenium/webdriver/support/escaper.rb +43 -0
  123. data/lib/selenium/webdriver/support/event_firing_bridge.rb +39 -41
  124. data/lib/selenium/webdriver/support/select.rb +45 -97
  125. data/lib/selenium/webdriver/support.rb +3 -2
  126. data/lib/selenium/webdriver/{iphone.rb → version.rb} +3 -7
  127. data/lib/selenium/webdriver.rb +36 -23
  128. data/lib/selenium-webdriver.rb +2 -2
  129. data/selenium-webdriver.gemspec +42 -29
  130. metadata +331 -262
  131. data/lib/selenium/client/base.rb +0 -151
  132. data/lib/selenium/client/driver.rb +0 -29
  133. data/lib/selenium/client/errors.rb +0 -28
  134. data/lib/selenium/client/extensions.rb +0 -132
  135. data/lib/selenium/client/idiomatic.rb +0 -507
  136. data/lib/selenium/client/javascript_expression_builder.rb +0 -135
  137. data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
  138. data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
  139. data/lib/selenium/client/legacy_driver.rb +0 -1722
  140. data/lib/selenium/client/protocol.rb +0 -123
  141. data/lib/selenium/client/selenium_helper.rb +0 -49
  142. data/lib/selenium/client.rb +0 -57
  143. data/lib/selenium/rake/server_task.rb +0 -176
  144. data/lib/selenium/webdriver/android/bridge.rb +0 -68
  145. data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
  146. data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
  147. data/lib/selenium/webdriver/common/html5/location.rb +0 -19
  148. data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
  149. data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
  150. data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
  151. data/lib/selenium/webdriver/ie/bridge.rb +0 -88
  152. data/lib/selenium/webdriver/ie/server.rb +0 -133
  153. data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
  154. data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
  155. data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
  156. data/lib/selenium/webdriver/remote/commands.rb +0 -211
  157. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
  158. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
  159. data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
  160. data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
  161. data/lib/selenium/webdriver/safari/server.rb +0 -187
  162. data/lib/selenium-client.rb +0 -21
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
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
- COMMANDS = {}
34
-
35
- #
36
- # Defines a wrapper method for a command, which ultimately calls #execute.
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
- # Initializes the bridge with the given server URL.
36
+ # Implements protocol handshake which:
56
37
  #
57
- # @param url [String] url for the remote server
58
- # @param http_client [Object] an HTTP client instance that implements the same protocol as Http::Default
59
- # @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.
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
- def initialize(opts = {})
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.send(desired_capabilities)
52
+ desired_capabilities = Capabilities.__send__(desired_capabilities)
79
53
  end
80
54
 
81
- uri = url.kind_of?(URI) ? url : URI.parse(url)
82
- uri.path += "/" unless uri.path =~ /\/$/
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
- def getNetworkConnection
339
- execute :getNetworkConnection
340
- end
341
-
342
- def setNetworkConnection(type)
343
- execute :setNetworkConnection, {}, :parameters => {:type => type}
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
- # javascript execution
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 executeScript(script, *args)
351
- assert_javascript_enabled
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
- # cookies
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
- def addCookie(cookie)
369
- execute :addCookie, {}, :cookie => cookie
370
- end
84
+ unless opts.empty?
85
+ raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
86
+ end
371
87
 
372
- def deleteCookie(name)
373
- execute :deleteCookie, :name => name
374
- end
88
+ uri = url.is_a?(URI) ? url : URI.parse(url)
89
+ uri.path += '/' unless uri.path =~ %r{\/$}
375
90
 
376
- def getAllCookies
377
- execute :getCookies
378
- end
91
+ http_client.server_url = uri
379
92
 
380
- def deleteAllCookies
381
- execute :deleteAllCookies
93
+ @http = http_client
94
+ @file_detector = nil
382
95
  end
383
96
 
384
97
  #
385
- # actions
98
+ # Creates session handling both OSS and W3C dialects.
386
99
  #
387
100
 
388
- def clickElement(element)
389
- execute :clickElement, :id => element
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
- def sendKeysToElement(element, keys)
427
- if @file_detector && local_file = @file_detector.call(keys)
428
- keys = upload(local_file)
429
- end
104
+ @session_id = response['sessionId']
105
+ oss_status = response['status']
106
+ value = response['value']
430
107
 
431
- execute :sendKeysToElement, {:id => element}, {:value => Array(keys)}
432
- end
108
+ if value.is_a?(Hash)
109
+ @session_id = value['sessionId'] if value.key?('sessionId')
433
110
 
434
- def upload(local_file)
435
- unless File.file?(local_file)
436
- raise Error::WebDriverError, "you may only upload files: #{local_file.inspect}"
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
- execute :uploadFile, {}, :file => Zipper.zip_file(local_file)
440
- end
118
+ raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
441
119
 
442
- def clearElement(element)
443
- execute :clearElement, :id => element
444
- end
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
- execute :touchScroll, {}, :xoffset => x, :yoffset => y
485
- end
486
- end
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
- # element properties
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 getActiveElement
588
- Element.new self, element_id_from(execute(:getActiveElement))
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 find_element_by(how, what, parent = nil)
593
- if parent
594
- id = execute :findChildElement, {:id => parent}, {:using => how, :value => what}
595
- else
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 raw_execute(command, opts = {}, command_hash = nil)
637
- verb, path = COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
638
- 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
639
157
 
640
- path[':session_id'] = @session_id if path.include?(":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
- puts "-> #{verb.to_s.upcase} #{path}" if $DEBUG
649
- http.call verb, path, command_hash
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::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
+ }
654
190
  end
655
191
 
656
192
  end # Bridge