selenium-webdriver 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
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