selenium-webdriver 0.0.17 → 0.0.18

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.
Files changed (77) hide show
  1. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  2. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  3. data/chrome/src/extension/background.js +64 -48
  4. data/chrome/src/extension/content_script.js +253 -132
  5. data/chrome/src/extension/manifest-nonwin.json +1 -1
  6. data/chrome/src/extension/manifest-win.json +1 -1
  7. data/chrome/src/extension/utils.js +8 -8
  8. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +9 -0
  9. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +38 -280
  10. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +119 -117
  11. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +36 -26
  12. data/common/src/js/abstractcommandprocessor.js +9 -11
  13. data/common/src/js/command.js +159 -83
  14. data/common/src/js/core/RemoteRunner.html +2 -2
  15. data/common/src/js/core/TestRunner-splash.html +3 -3
  16. data/common/src/js/core/TestRunner.html +5 -17
  17. data/common/src/js/core/scripts/htmlutils.js +4208 -2506
  18. data/common/src/js/core/scripts/selenium-api.js +2 -2
  19. data/common/src/js/core/scripts/selenium-browserbot.js +66 -58
  20. data/common/src/js/core/scripts/selenium-version.js +1 -1
  21. data/common/src/js/localcommandprocessor.js +5 -19
  22. data/common/src/js/testcase.js +2 -0
  23. data/common/src/js/webdriver.js +63 -93
  24. data/common/src/js/webelement.js +40 -42
  25. data/common/src/rb/lib/selenium/webdriver.rb +23 -14
  26. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +8 -35
  27. data/common/src/rb/lib/selenium/webdriver/child_process.rb +2 -0
  28. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +1 -0
  29. data/common/src/rb/lib/selenium/webdriver/core_ext/string.rb +5 -0
  30. data/common/src/rb/lib/selenium/webdriver/driver.rb +20 -15
  31. data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +7 -2
  32. data/common/src/rb/lib/selenium/webdriver/element.rb +11 -2
  33. data/common/src/rb/lib/selenium/webdriver/error.rb +9 -5
  34. data/common/src/rb/lib/selenium/webdriver/keys.rb +1 -2
  35. data/common/src/rb/lib/selenium/webdriver/navigation.rb +16 -0
  36. data/common/src/rb/lib/selenium/webdriver/options.rb +32 -0
  37. data/common/src/rb/lib/selenium/webdriver/platform.rb +17 -1
  38. data/firefox/prebuilt/Win32/Release/webdriver-firefox.dll +0 -0
  39. data/firefox/src/extension/components/dispatcher.js +492 -0
  40. data/firefox/src/extension/components/driver-component.js +4 -1
  41. data/firefox/src/extension/components/errorcode.js +70 -0
  42. data/firefox/src/extension/components/firefoxDriver.js +173 -154
  43. data/firefox/src/extension/components/nsCommandProcessor.js +171 -132
  44. data/firefox/src/extension/components/promptService.js +5 -5
  45. data/firefox/src/extension/components/request.js +219 -0
  46. data/firefox/src/extension/components/response.js +276 -0
  47. data/firefox/src/extension/components/session.js +281 -0
  48. data/firefox/src/extension/components/sessionstore.js +226 -0
  49. data/firefox/src/extension/components/socketListener.js +350 -100
  50. data/firefox/src/extension/components/utils.js +166 -98
  51. data/firefox/src/extension/components/webdriverserver.js +9 -5
  52. data/firefox/src/extension/components/wrappedElement.js +189 -166
  53. data/firefox/src/extension/install.rdf +1 -1
  54. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +2 -0
  55. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +39 -33
  56. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +7 -421
  57. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +7 -64
  58. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +2 -3
  59. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +54 -10
  60. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -0
  61. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +6 -0
  62. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  63. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  64. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +2 -0
  65. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +38 -13
  66. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +9 -2
  67. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +5 -0
  68. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +2 -0
  69. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +42 -38
  70. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +56 -47
  71. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +26 -26
  72. data/remote/client/src/rb/lib/selenium/webdriver/remote/patron_http_client.rb +58 -0
  73. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +10 -12
  74. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +2 -17
  75. metadata +44 -23
  76. data/common/src/js/context.js +0 -58
  77. data/firefox/src/extension/components/context.js +0 -37
@@ -7,19 +7,13 @@ module Selenium
7
7
  #
8
8
  # Low level bridge to the remote server, through which the rest of the API works.
9
9
  #
10
- # @api private
10
+ # @private
11
11
  #
12
12
 
13
13
  class Bridge
14
14
  include Find
15
15
  include BridgeHelper
16
16
 
17
- DEFAULT_OPTIONS = {
18
- :url => "http://localhost:4444/wd/hub",
19
- :http_client => DefaultHttpClient,
20
- :desired_capabilities => Capabilities.firefox
21
- }
22
-
23
17
  #
24
18
  # Defines a wrapper method for a command, which ultimately calls #execute.
25
19
  #
@@ -27,10 +21,7 @@ module Selenium
27
21
  # name of the resulting method
28
22
  # @param url [String]
29
23
  # a URL template, which can include some arguments, much like the definitions on the server.
30
- # the :session_id and :context parameters are implicitly handled, but the remainder will become
31
- # required method arguments.
32
- # e.g., "session/:session_id/:context/element/:id/text" will define a method that takes id
33
- # as it's first argument.
24
+ # the :session_id parameter is implicitly handled, but the remainder will become required method arguments.
34
25
  # @param verb [Symbol]
35
26
  # the appropriate http verb, such as :get, :post, or :delete
36
27
  #
@@ -51,7 +42,7 @@ module Selenium
51
42
  #
52
43
 
53
44
  def initialize(opts = {})
54
- opts = DEFAULT_OPTIONS.merge(opts)
45
+ opts = default_options.merge(opts)
55
46
  http_client_class = opts.delete(:http_client)
56
47
  desired_capabilities = opts.delete(:desired_capabilities)
57
48
  url = opts.delete(:url)
@@ -71,7 +62,6 @@ module Selenium
71
62
  uri = URI.parse(url)
72
63
  uri.path += "/" unless uri.path =~ /\/$/
73
64
 
74
- @context = "context"
75
65
  @http = http_client_class.new uri
76
66
  @capabilities = create_session(desired_capabilities)
77
67
  end
@@ -92,17 +82,15 @@ module Selenium
92
82
  @session_id || raise(Error::WebDriverError, "no current session exists")
93
83
  end
94
84
 
95
-
96
85
  def create_session(desired_capabilities)
97
- resp = raw_execute :newSession, {}, desired_capabilities
86
+ resp = raw_execute :newSession, {}, :desiredCapabilities => desired_capabilities
98
87
  @session_id = resp['sessionId'] || raise(Error::WebDriverError, 'no sessionId in returned payload')
99
- @context = resp['context']
100
88
 
101
89
  Capabilities.json_create resp['value']
102
90
  end
103
91
 
104
92
  def get(url)
105
- execute :get, {}, url
93
+ execute :get, {}, :url => url
106
94
  end
107
95
 
108
96
  def goBack
@@ -134,15 +122,15 @@ module Selenium
134
122
  end
135
123
 
136
124
  def switchToWindow(name)
137
- execute :switchToWindow, :name => name
125
+ execute :switchToWindow, {}, :name => name
138
126
  end
139
127
 
140
128
  def switchToFrame(id)
141
- execute :switchToFrame, :id => id
129
+ execute :switchToFrame, {}, :id => id
142
130
  end
143
131
 
144
132
  def switchToDefaultContent
145
- execute :switchToFrame, :id => nil
133
+ execute :switchToFrame, {}, :id => nil
146
134
  end
147
135
 
148
136
  def quit
@@ -166,7 +154,7 @@ module Selenium
166
154
  end
167
155
 
168
156
  def setSpeed(value)
169
- execute :setSpeed, {}, value
157
+ execute :setSpeed, {}, :speed => value
170
158
  end
171
159
 
172
160
  def getSpeed
@@ -178,18 +166,16 @@ module Selenium
178
166
  raise Error::UnsupportedOperationError, "underlying webdriver instance does not support javascript"
179
167
  end
180
168
 
181
- typed_args = args.map { |arg| wrap_script_argument(arg) }
182
- response = raw_execute :executeScript, {}, script, typed_args
183
-
184
- unwrap_script_argument response['value']
169
+ result = execute :executeScript, {}, :script => script, :args => args
170
+ unwrap_script_result result
185
171
  end
186
172
 
187
173
  def addCookie(cookie)
188
- execute :addCookie, {}, cookie
174
+ execute :addCookie, {}, :cookie => cookie
189
175
  end
190
176
 
191
177
  def deleteCookie(name)
192
- execute :deleteCookie, :name => name
178
+ execute :deleteCookieNamed, :name => name
193
179
  end
194
180
 
195
181
  def getAllCookies
@@ -339,18 +325,20 @@ module Selenium
339
325
  end
340
326
 
341
327
  def dragElement(element, rigth_by, down_by)
342
- # TODO: why is element sent twice in the payload?
343
- execute :dragElement, {:id => element}, element, rigth_by, down_by
328
+ execute :dragElement, {:id => element}, :x => rigth_by, :y => down_by
329
+ end
330
+
331
+ def getCapabilities
332
+ Capabilities.json_create execute(:getCapabilities)
344
333
  end
345
334
 
346
335
  private
347
336
 
348
337
  def find_element_by(how, what, parent = nil)
349
338
  if parent
350
- # TODO: why is how sent twice in the payload?
351
- id = execute :findChildElement, {:id => parent, :using => how}, {:using => how, :value => what}
339
+ id = execute :findChildElement, {:id => parent}, {:using => how, :value => what}
352
340
  else
353
- id = execute :findElement, {}, how, what
341
+ id = execute :findElement, {}, {:using => how, :value => what}
354
342
  end
355
343
 
356
344
  Element.new self, element_id_from(id)
@@ -359,9 +347,9 @@ module Selenium
359
347
  def find_elements_by(how, what, parent = nil)
360
348
  if parent
361
349
  # TODO: why is how sent twice in the payload?
362
- ids = execute :findChildElements, {:id => parent, :using => how}, {:using => how, :value => what}
350
+ ids = execute :findChildElements, {:id => parent}, {:using => how, :value => what}
363
351
  else
364
- ids = execute :findElements, {}, how, what
352
+ ids = execute :findElements, {}, {:using => how, :value => what}
365
353
  end
366
354
 
367
355
  ids.map { |id| Element.new self, element_id_from(id) }
@@ -385,21 +373,37 @@ module Selenium
385
373
  # Returns a WebDriver::Remote::Response instance
386
374
  #
387
375
 
388
- def raw_execute(command, opts = {}, *args)
376
+ def raw_execute(command, opts = {}, command_hash = nil)
389
377
  verb, path = COMMANDS[command] || raise("unknown command #{command.inspect}")
390
378
  path = path.dup
391
379
 
392
380
  path[':session_id'] = @session_id if path.include?(":session_id")
393
- path[':context'] = @context if path.include?(":context")
394
381
 
395
382
  begin
396
- opts.each { |key, value| path[key.inspect] = URI.escape(value.to_s) }
383
+ opts.each { |key, value| path[key.inspect] = URI.escape(value.to_s)}
397
384
  rescue IndexError
398
385
  raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
399
386
  end
400
387
 
401
388
  puts "-> #{verb.to_s.upcase} #{path}" if $DEBUG
402
- http.call verb, path, *args
389
+ http.call verb, path, command_hash
390
+ end
391
+
392
+ def default_options
393
+ {
394
+ :url => "http://localhost:4444/wd/hub",
395
+ # TODO(jari): enable Patron when http://github.com/toland/patron/issues/issue/13 is fixed
396
+ :http_client => DefaultHttpClient,
397
+ :desired_capabilities => Capabilities.firefox
398
+ }
399
+ end
400
+
401
+ def http_client_class
402
+ require "selenium/webdriver/remote/patron_http_client"
403
+ PatronHttpClient
404
+ rescue LoadError
405
+ # patron not available
406
+ DefaultHttpClient
403
407
  end
404
408
 
405
409
  end # Bridge
@@ -1,53 +1,62 @@
1
+ # @private
1
2
  class Selenium::WebDriver::Remote::Bridge
2
- command :addCookie, :post, "session/:session_id/:context/cookie"
3
- command :goBack, :post, "session/:session_id/:context/back"
4
- command :clearElement, :post, "session/:session_id/:context/element/:id/clear"
5
- command :clickElement, :post, "session/:session_id/:context/element/:id/click"
6
- command :close, :delete, "session/:session_id/:context/window"
7
- command :getCurrentUrl, :get, "session/:session_id/:context/url"
8
- command :deleteAllCookies, :delete, "session/:session_id/:context/cookie"
9
- command :deleteCookie, :delete, "session/:session_id/:context/cookie/:name"
10
- command :dragElement, :post, "session/:session_id/:context/element/:id/drag"
11
- command :elementEquals, :get, "session/:session_id/:context/element/:id/equals/:other"
12
- command :executeScript, :post, "session/:session_id/:context/execute"
13
- command :findElement, :post, "session/:session_id/:context/element"
14
- command :findElements, :post, "session/:session_id/:context/elements"
15
- command :findChildElement, :post, "session/:session_id/:context/element/:id/element/:using"
16
- command :findChildElements, :post, "session/:session_id/:context/element/:id/elements/:using"
17
- command :goForward, :post, "session/:session_id/:context/forward"
18
- command :get, :post, "session/:session_id/:context/url"
19
- command :getActiveElement, :post, "session/:session_id/:context/element/active"
20
- command :getAllCookies, :get, "session/:session_id/:context/cookie"
21
- # command :getCookie # TODO: getCookie
22
- command :getCurrentWindowHandle, :get, "session/:session_id/:context/window_handle"
23
- command :getElementAttribute, :get, "session/:session_id/:context/element/:id/attribute/:name"
24
- command :getElementLocation, :get, "session/:session_id/:context/element/:id/location"
25
- command :getElementSize, :get, "session/:session_id/:context/element/:id/size"
26
- command :getElementText, :get, "session/:session_id/:context/element/:id/text"
27
- command :getElementValue, :get, "session/:session_id/:context/element/:id/value"
28
- command :getSpeed, :get, "session/:session_id/:context/speed"
29
- command :getElementTagName, :get, "session/:session_id/:context/element/:id/name"
30
- command :getTitle, :get, "session/:session_id/:context/title"
31
- command :getElementValueOfCssProperty, :get, "session/:session_id/:context/element/:id/css/:property_name"
32
- command :getVisible, :get, "session/:session_id/:context/visible"
33
- command :getWindowHandles, :get, "session/:session_id/:context/window_handles"
34
- command :hoverOverElement, :post, "session/:session_id/:context/element/:id/hover"
35
- command :isElementDisplayed, :get, "session/:session_id/:context/element/:id/displayed"
36
- command :isElementEnabled, :get, "session/:session_id/:context/element/:id/enabled"
37
- command :isElementSelected, :get, "session/:session_id/:context/element/:id/selected"
3
+
4
+ #
5
+ # http://code.google.com/p/selenium/wiki/JsonWireProtocol#Command_Reference
6
+ #
7
+
38
8
  command :newSession, :post, "session"
39
- command :getPageSource, :get, "session/:session_id/:context/source"
9
+ command :getCapabilities, :get, "session/:session_id"
40
10
  command :quit, :delete, "session/:session_id"
41
- command :refresh, :post, "session/:session_id/:context/refresh"
42
- command :screenshot, :get, "session/:session_id/:context/screenshot"
43
- command :sendKeysToElement, :post, "session/:session_id/:context/element/:id/value"
44
- command :setElementSelected, :post, "session/:session_id/:context/element/:id/selected"
45
- command :setSpeed, :post, "session/:session_id/:context/speed"
46
- command :setVisible, :post, "session/:session_id/:context/visible"
47
- command :submitElement, :post, "session/:session_id/:context/element/:id/submit"
48
- command :switchToFrame, :post, "session/:session_id/:context/frame/:id"
11
+ command :getCurrentWindowHandle, :get, "session/:session_id/window_handle"
12
+ command :getWindowHandles, :get, "session/:session_id/window_handles"
13
+ command :getCurrentUrl, :get, "session/:session_id/url"
14
+ command :get, :post, "session/:session_id/url"
15
+ command :goForward, :post, "session/:session_id/forward"
16
+ command :goBack, :post, "session/:session_id/back"
17
+ command :refresh, :post, "session/:session_id/refresh"
18
+ command :executeScript, :post, "session/:session_id/execute"
19
+ command :screenshot, :get, "session/:session_id/screenshot"
20
+ command :switchToFrame, :post, "session/:session_id/frame"
21
+ command :switchToWindow, :post, "session/:session_id/window"
22
+ command :getSpeed, :get, "session/:session_id/speed"
23
+ command :setSpeed, :post, "session/:session_id/speed"
24
+ command :getAllCookies, :get, "session/:session_id/cookie"
25
+ command :addCookie, :post, "session/:session_id/cookie"
26
+ command :deleteAllCookies, :delete, "session/:session_id/cookie"
27
+ command :deleteCookieNamed, :delete, "session/:session_id/cookie/:name"
28
+ command :getPageSource, :get, "session/:session_id/source"
29
+ command :getTitle, :get, "session/:session_id/title"
30
+ command :findElement, :post, "session/:session_id/element"
31
+ command :findElements, :post, "session/:session_id/elements"
32
+ command :getActiveElement, :post, "session/:session_id/element/active"
33
+ command :describeElement, :get, "session/:session_id/element/:id"
34
+ command :findChildElement, :post, "session/:session_id/element/:id/element"
35
+ command :findChildElements, :post, "session/:session_id/element/:id/elements"
36
+ command :clickElement, :post, "session/:session_id/element/:id/click"
37
+ command :submitElement, :post, "session/:session_id/element/:id/submit"
38
+ command :getElementValue, :get, "session/:session_id/element/:id/value"
39
+ command :sendKeysToElement, :post, "session/:session_id/element/:id/value"
40
+ command :getElementTagName, :get, "session/:session_id/element/:id/name"
41
+ command :clearElement, :post, "session/:session_id/element/:id/clear"
42
+ command :isElementSelected, :get, "session/:session_id/element/:id/selected"
43
+ command :setElementSelected, :post, "session/:session_id/element/:id/selected"
44
+ command :toggleElement, :post, "session/:session_id/element/:id/toggle"
45
+ command :isElementEnabled, :get, "session/:session_id/element/:id/enabled"
46
+ command :getElementAttribute, :get, "session/:session_id/element/:id/attribute/:name"
47
+ command :elementEquals, :get, "session/:session_id/element/:id/equals/:other"
48
+ command :isElementDisplayed, :get, "session/:session_id/element/:id/displayed"
49
+ command :getElementLocation, :get, "session/:session_id/element/:id/location"
50
+ command :getElementLocationInView, :get, "session/:session_id/element/:id/location_in_view"
51
+ command :getElementSize, :get, "session/:session_id/element/:id/size"
52
+ command :hoverOverElement, :post, "session/:session_id/element/:id/hover"
53
+ command :dragElement, :post, "session/:session_id/element/:id/drag"
54
+ command :getElementValueOfCssProperty, :get, "session/:session_id/element/:id/css/:property_name"
55
+
56
+ command :close, :delete, "session/:session_id/window"
57
+ command :getElementText, :get, "session/:session_id/element/:id/text"
58
+ command :getVisible, :get, "session/:session_id/visible"
59
+ command :setVisible, :post, "session/:session_id/visible"
49
60
  # command :switchToFrameByIndex # TODO: switchToFrameByIndex
50
61
  # command :switchToDefaultContent # TODO: switchToDefaultContent
51
- command :switchToWindow, :post, "session/:session_id/:context/window/:name"
52
- command :toggleElement, :post, "session/:session_id/:context/element/:id/toggle"
53
62
  end
@@ -3,45 +3,33 @@ require "net/http"
3
3
  module Selenium
4
4
  module WebDriver
5
5
  module Remote
6
+
7
+ # @private
6
8
  class DefaultHttpClient
7
9
  CONTENT_TYPE = "application/json"
8
- DEFAULT_HEADERS = { "Accept" => CONTENT_TYPE }
9
-
10
- class RetryException < StandardError; end
10
+ DEFAULT_HEADERS = { "Accept" => CONTENT_TYPE, "Content-Length" => "0" }
11
11
 
12
12
  def initialize(url)
13
13
  @server_url = url
14
14
  end
15
15
 
16
- def call(verb, url, *args)
16
+ def call(verb, url, command_hash)
17
17
  response = nil
18
18
  url = @server_url.merge(url) unless url.kind_of?(URI)
19
19
  headers = DEFAULT_HEADERS.dup
20
20
 
21
- if args.any?
22
- headers.merge!("Content-Type" => "#{CONTENT_TYPE}; charset=utf-8")
23
- payload = args.to_json
24
- puts " >>> #{payload}" if $DEBUG
25
- end
26
-
27
- begin
28
- request = Net::HTTP.const_get(verb.to_s.capitalize).new(url.path, headers)
21
+ if command_hash
22
+ payload = command_hash.to_json
23
+ headers["Content-Type"] = "#{CONTENT_TYPE}; charset=utf-8"
24
+ headers["Content-Length"] = payload.bytesize.to_s if [:post, :put].include?(verb)
29
25
 
30
- # TODO: should be checking against a maximum redirect count
31
- http.request(request, payload) do |res|
32
- if res.kind_of? Net::HTTPRedirection
33
- verb, payload = :get, nil
34
- url = URI.parse(res["Location"])
35
- raise RetryException
36
- else
37
- response = create_response(res)
38
- end
26
+ if $DEBUG
27
+ puts " >>> #{payload}"
28
+ puts " > #{headers.inspect}"
39
29
  end
40
-
41
- response
42
- rescue RetryException
43
- retry
44
30
  end
31
+
32
+ request verb, url, headers, payload
45
33
  end
46
34
 
47
35
  private
@@ -51,6 +39,18 @@ module Selenium
51
39
  @http ||= Net::HTTP.new @server_url.host, @server_url.port
52
40
  end
53
41
 
42
+ def request(verb, url, headers, payload)
43
+ request = Net::HTTP.const_get(verb.to_s.capitalize).new(url.path, headers)
44
+ response = http.request(request, payload)
45
+
46
+ # TODO: should be checking against a maximum redirect count
47
+ if response.kind_of? Net::HTTPRedirection
48
+ request(:get, URI.parse(response['Location']), DEFAULT_HEADERS.dup, nil)
49
+ else
50
+ create_response response
51
+ end
52
+ end
53
+
54
54
  def create_response(res)
55
55
  puts "<- #{res.body}\n" if $DEBUG
56
56
  if res.content_type == CONTENT_TYPE
@@ -68,4 +68,4 @@ module Selenium
68
68
  end # DefaultHttpClient
69
69
  end # Remote
70
70
  end # WebDriver
71
- end # Selenium
71
+ end # Selenium
@@ -0,0 +1,58 @@
1
+ require "patron"
2
+
3
+ module Selenium
4
+ module WebDriver
5
+ module Remote
6
+
7
+ # @private
8
+ class PatronHttpClient
9
+ CONTENT_TYPE = "application/json"
10
+ DEFAULT_HEADERS = { "Accept" => CONTENT_TYPE, "Content-Length" => "0" }
11
+
12
+ def initialize(url)
13
+ @session = Patron::Session.new
14
+ @session.base_url = url
15
+ end
16
+
17
+ def call(verb, url, command_hash)
18
+ DEFAULT_HEADERS.each do |key, val|
19
+ @session.headers[key] = val
20
+ end
21
+
22
+ if command_hash
23
+ payload = command_hash.to_json
24
+ @session.headers['Content-Type'] = "#{CONTENT_TYPE}; charset=utf-8;"
25
+ @session.headers['Content-Length'] = payload.bytesize.to_s if [:post, :put].include?(verb)
26
+ if $DEBUG
27
+ puts " >>> #{payload}"
28
+ puts " > #{@session.headers.inspect}"
29
+ end
30
+ end
31
+
32
+ if [:post, :put].include?(verb)
33
+ create_response @session.send(verb, url, payload || '')
34
+ else
35
+ create_response @session.send(verb, url)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def create_response(res)
42
+ puts "<- #{res.body}\n" if $DEBUG
43
+ if res.headers['Content-Type'].include? CONTENT_TYPE
44
+ Response.new do |r|
45
+ r.code = res.status.to_i
46
+ r.payload = JSON.parse(res.body.strip)
47
+ end
48
+ elsif res.status == '204'
49
+ Response.new { |r| r.code = res.code.to_i }
50
+ else
51
+ raise "Unexpected content type: #{res.headers.inspect} (#{res.status})\n#{res.body}"
52
+ end
53
+ end
54
+
55
+ end # PatronHttpClient
56
+ end # Remote
57
+ end # WebDriver
58
+ end # Selenium
@@ -1,6 +1,8 @@
1
1
  module Selenium
2
2
  module WebDriver
3
3
  module Remote
4
+
5
+ # @private
4
6
  class Response
5
7
 
6
8
  attr_accessor :code
@@ -12,12 +14,11 @@ module Selenium
12
14
  end
13
15
 
14
16
  def error
15
- if payload['error']
16
- value = payload['value']
17
- # the remote server gets this wrong, where the value is double encoded as JSON
18
- # the iphone driver does the right thing
19
- value.kind_of?(String) ? JSON.parse(value) : value
20
- end
17
+ Error.for_code(payload['status'])
18
+ end
19
+
20
+ def error_message
21
+ payload['value']['message']
21
22
  end
22
23
 
23
24
  def [](key)
@@ -31,14 +32,11 @@ module Selenium
31
32
  private
32
33
 
33
34
  def assert_ok
34
- if @code.nil? || @code > 400
35
+ if @code.nil? || @code >= 400
35
36
  if e = error()
36
- raise(
37
- Error.for_remote_class(e['class']),
38
- e['message'] || self
39
- )
37
+ raise(e, error_message)
40
38
  else
41
- raise ServerError, self
39
+ raise Error::ServerError, self
42
40
  end
43
41
  end
44
42
  end