mutle-webrat 0.7.2.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. data/.document +4 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +13 -0
  4. data/History.txt +450 -0
  5. data/MIT-LICENSE.txt +19 -0
  6. data/README.rdoc +85 -0
  7. data/Rakefile +143 -0
  8. data/Thorfile +118 -0
  9. data/install.rb +1 -0
  10. data/lib/webrat.rb +18 -0
  11. data/lib/webrat/adapters/mechanize.rb +94 -0
  12. data/lib/webrat/adapters/merb.rb +11 -0
  13. data/lib/webrat/adapters/rack.rb +29 -0
  14. data/lib/webrat/adapters/rails.rb +77 -0
  15. data/lib/webrat/adapters/sinatra.rb +9 -0
  16. data/lib/webrat/core.rb +13 -0
  17. data/lib/webrat/core/configuration.rb +114 -0
  18. data/lib/webrat/core/elements/area.rb +31 -0
  19. data/lib/webrat/core/elements/element.rb +33 -0
  20. data/lib/webrat/core/elements/field.rb +438 -0
  21. data/lib/webrat/core/elements/form.rb +127 -0
  22. data/lib/webrat/core/elements/label.rb +31 -0
  23. data/lib/webrat/core/elements/link.rb +95 -0
  24. data/lib/webrat/core/elements/select_option.rb +48 -0
  25. data/lib/webrat/core/locators.rb +20 -0
  26. data/lib/webrat/core/locators/area_locator.rb +38 -0
  27. data/lib/webrat/core/locators/button_locator.rb +54 -0
  28. data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
  29. data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
  30. data/lib/webrat/core/locators/field_locator.rb +25 -0
  31. data/lib/webrat/core/locators/field_named_locator.rb +41 -0
  32. data/lib/webrat/core/locators/form_locator.rb +19 -0
  33. data/lib/webrat/core/locators/label_locator.rb +34 -0
  34. data/lib/webrat/core/locators/link_locator.rb +82 -0
  35. data/lib/webrat/core/locators/locator.rb +20 -0
  36. data/lib/webrat/core/locators/select_option_locator.rb +59 -0
  37. data/lib/webrat/core/logging.rb +23 -0
  38. data/lib/webrat/core/matchers.rb +4 -0
  39. data/lib/webrat/core/matchers/have_content.rb +68 -0
  40. data/lib/webrat/core/matchers/have_selector.rb +74 -0
  41. data/lib/webrat/core/matchers/have_tag.rb +21 -0
  42. data/lib/webrat/core/matchers/have_xpath.rb +124 -0
  43. data/lib/webrat/core/methods.rb +73 -0
  44. data/lib/webrat/core/mime.rb +18 -0
  45. data/lib/webrat/core/save_and_open_page.rb +28 -0
  46. data/lib/webrat/core/scope.rb +366 -0
  47. data/lib/webrat/core/session.rb +303 -0
  48. data/lib/webrat/core/xml.rb +72 -0
  49. data/lib/webrat/core_extensions/blank.rb +58 -0
  50. data/lib/webrat/core_extensions/deprecate.rb +8 -0
  51. data/lib/webrat/core_extensions/detect_mapped.rb +12 -0
  52. data/lib/webrat/core_extensions/meta_class.rb +6 -0
  53. data/lib/webrat/core_extensions/nil_to_query_string.rb +5 -0
  54. data/lib/webrat/core_extensions/tcp_socket.rb +27 -0
  55. data/lib/webrat/integrations/merb.rb +10 -0
  56. data/lib/webrat/integrations/rack.rb +9 -0
  57. data/lib/webrat/integrations/rails.rb +25 -0
  58. data/lib/webrat/integrations/rspec-rails.rb +11 -0
  59. data/lib/webrat/integrations/selenium.rb +11 -0
  60. data/lib/webrat/merb.rb +9 -0
  61. data/lib/webrat/rspec-rails.rb +2 -0
  62. data/lib/webrat/selenium.rb +70 -0
  63. data/lib/webrat/selenium/application_server_factory.rb +43 -0
  64. data/lib/webrat/selenium/application_servers.rb +5 -0
  65. data/lib/webrat/selenium/application_servers/base.rb +46 -0
  66. data/lib/webrat/selenium/application_servers/external.rb +26 -0
  67. data/lib/webrat/selenium/application_servers/merb.rb +50 -0
  68. data/lib/webrat/selenium/application_servers/rack.rb +36 -0
  69. data/lib/webrat/selenium/application_servers/rails.rb +44 -0
  70. data/lib/webrat/selenium/application_servers/sinatra.rb +37 -0
  71. data/lib/webrat/selenium/location_strategy_javascript/button.js +19 -0
  72. data/lib/webrat/selenium/location_strategy_javascript/label.js +48 -0
  73. data/lib/webrat/selenium/location_strategy_javascript/webrat.js +6 -0
  74. data/lib/webrat/selenium/location_strategy_javascript/webratlink.js +32 -0
  75. data/lib/webrat/selenium/location_strategy_javascript/webratlinkwithin.js +15 -0
  76. data/lib/webrat/selenium/location_strategy_javascript/webratselectwithoption.js +5 -0
  77. data/lib/webrat/selenium/matchers.rb +4 -0
  78. data/lib/webrat/selenium/matchers/have_content.rb +78 -0
  79. data/lib/webrat/selenium/matchers/have_selector.rb +57 -0
  80. data/lib/webrat/selenium/matchers/have_tag.rb +72 -0
  81. data/lib/webrat/selenium/matchers/have_xpath.rb +53 -0
  82. data/lib/webrat/selenium/selenium_extensions.js +6 -0
  83. data/lib/webrat/selenium/selenium_rc_server.rb +89 -0
  84. data/lib/webrat/selenium/selenium_session.rb +276 -0
  85. data/lib/webrat/selenium/silence_stream.rb +18 -0
  86. data/spec/fakes/test_adapter.rb +33 -0
  87. data/spec/integration/mechanize/Rakefile +7 -0
  88. data/spec/integration/mechanize/config.ru +2 -0
  89. data/spec/integration/mechanize/sample_app.rb +35 -0
  90. data/spec/integration/mechanize/spec/mechanize_spec.rb +30 -0
  91. data/spec/integration/mechanize/spec/spec_helper.rb +29 -0
  92. data/spec/integration/merb/.gitignore +21 -0
  93. data/spec/integration/merb/Rakefile +35 -0
  94. data/spec/integration/merb/app/controllers/application.rb +2 -0
  95. data/spec/integration/merb/app/controllers/exceptions.rb +13 -0
  96. data/spec/integration/merb/app/controllers/testing.rb +27 -0
  97. data/spec/integration/merb/app/views/exceptions/not_acceptable.html.erb +63 -0
  98. data/spec/integration/merb/app/views/exceptions/not_found.html.erb +47 -0
  99. data/spec/integration/merb/app/views/layout/application.html.erb +12 -0
  100. data/spec/integration/merb/app/views/testing/show_form.html.erb +27 -0
  101. data/spec/integration/merb/app/views/testing/upload.html.erb +9 -0
  102. data/spec/integration/merb/config/environments/development.rb +15 -0
  103. data/spec/integration/merb/config/environments/rake.rb +11 -0
  104. data/spec/integration/merb/config/environments/test.rb +14 -0
  105. data/spec/integration/merb/config/init.rb +25 -0
  106. data/spec/integration/merb/config/rack.rb +11 -0
  107. data/spec/integration/merb/config/router.rb +34 -0
  108. data/spec/integration/merb/spec/spec.opts +1 -0
  109. data/spec/integration/merb/spec/spec_helper.rb +26 -0
  110. data/spec/integration/merb/spec/webrat_spec.rb +39 -0
  111. data/spec/integration/merb/tasks/merb.thor/app_script.rb +31 -0
  112. data/spec/integration/merb/tasks/merb.thor/common.rb +64 -0
  113. data/spec/integration/merb/tasks/merb.thor/gem_ext.rb +124 -0
  114. data/spec/integration/merb/tasks/merb.thor/main.thor +150 -0
  115. data/spec/integration/merb/tasks/merb.thor/ops.rb +93 -0
  116. data/spec/integration/merb/tasks/merb.thor/utils.rb +40 -0
  117. data/spec/integration/rack/Rakefile +5 -0
  118. data/spec/integration/rack/app.rb +89 -0
  119. data/spec/integration/rack/test/helper.rb +20 -0
  120. data/spec/integration/rack/test/webrat_rack_test.rb +74 -0
  121. data/spec/integration/rails/.gitignore +3 -0
  122. data/spec/integration/rails/Rakefile +30 -0
  123. data/spec/integration/rails/app/controllers/application_controller.rb +15 -0
  124. data/spec/integration/rails/app/controllers/buttons_controller.rb +7 -0
  125. data/spec/integration/rails/app/controllers/fields_controller.rb +4 -0
  126. data/spec/integration/rails/app/controllers/links_controller.rb +7 -0
  127. data/spec/integration/rails/app/controllers/webrat_controller.rb +46 -0
  128. data/spec/integration/rails/app/helpers/buttons_helper.rb +2 -0
  129. data/spec/integration/rails/app/helpers/fields_helper.rb +2 -0
  130. data/spec/integration/rails/app/helpers/links_helper.rb +2 -0
  131. data/spec/integration/rails/app/views/buttons/show.html.erb +9 -0
  132. data/spec/integration/rails/app/views/fields/show.html.erb +9 -0
  133. data/spec/integration/rails/app/views/links/show.html.erb +5 -0
  134. data/spec/integration/rails/app/views/webrat/before_redirect_form.html.erb +4 -0
  135. data/spec/integration/rails/app/views/webrat/buttons.html.erb +9 -0
  136. data/spec/integration/rails/app/views/webrat/form.html.erb +28 -0
  137. data/spec/integration/rails/app/views/webrat/within.html.erb +3 -0
  138. data/spec/integration/rails/config/boot.rb +109 -0
  139. data/spec/integration/rails/config/environment.rb +12 -0
  140. data/spec/integration/rails/config/environments/development.rb +17 -0
  141. data/spec/integration/rails/config/environments/selenium.rb +22 -0
  142. data/spec/integration/rails/config/environments/test.rb +22 -0
  143. data/spec/integration/rails/config/initializers/inflections.rb +10 -0
  144. data/spec/integration/rails/config/initializers/mime_types.rb +5 -0
  145. data/spec/integration/rails/config/initializers/new_rails_defaults.rb +17 -0
  146. data/spec/integration/rails/config/locales/en.yml +5 -0
  147. data/spec/integration/rails/config/routes.rb +19 -0
  148. data/spec/integration/rails/public/404.html +30 -0
  149. data/spec/integration/rails/public/422.html +30 -0
  150. data/spec/integration/rails/public/500.html +33 -0
  151. data/spec/integration/rails/script/about +4 -0
  152. data/spec/integration/rails/script/console +3 -0
  153. data/spec/integration/rails/script/dbconsole +3 -0
  154. data/spec/integration/rails/script/destroy +3 -0
  155. data/spec/integration/rails/script/generate +3 -0
  156. data/spec/integration/rails/script/performance/benchmarker +3 -0
  157. data/spec/integration/rails/script/performance/profiler +3 -0
  158. data/spec/integration/rails/script/performance/request +3 -0
  159. data/spec/integration/rails/script/plugin +3 -0
  160. data/spec/integration/rails/script/process/inspector +3 -0
  161. data/spec/integration/rails/script/process/reaper +3 -0
  162. data/spec/integration/rails/script/process/spawner +3 -0
  163. data/spec/integration/rails/script/runner +3 -0
  164. data/spec/integration/rails/script/server +3 -0
  165. data/spec/integration/rails/test/integration/button_click_test.rb +66 -0
  166. data/spec/integration/rails/test/integration/fill_in_test.rb +24 -0
  167. data/spec/integration/rails/test/integration/link_click_test.rb +27 -0
  168. data/spec/integration/rails/test/integration/webrat_test.rb +123 -0
  169. data/spec/integration/rails/test/test_helper.rb +27 -0
  170. data/spec/integration/sinatra/Rakefile +5 -0
  171. data/spec/integration/sinatra/classic_app.rb +63 -0
  172. data/spec/integration/sinatra/modular_app.rb +15 -0
  173. data/spec/integration/sinatra/test/classic_app_test.rb +38 -0
  174. data/spec/integration/sinatra/test/modular_app_test.rb +18 -0
  175. data/spec/integration/sinatra/test/test_helper.rb +16 -0
  176. data/spec/private/core/configuration_spec.rb +87 -0
  177. data/spec/private/core/field_spec.rb +83 -0
  178. data/spec/private/core/form_spec.rb +51 -0
  179. data/spec/private/core/link_spec.rb +24 -0
  180. data/spec/private/core/session_spec.rb +182 -0
  181. data/spec/private/mechanize/mechanize_adapter_spec.rb +96 -0
  182. data/spec/private/nokogiri_spec.rb +77 -0
  183. data/spec/private/rails/attaches_file_spec.rb +114 -0
  184. data/spec/private/rails/rails_adapter_spec.rb +79 -0
  185. data/spec/private/selenium/application_servers/rails_spec.rb +26 -0
  186. data/spec/public/basic_auth_spec.rb +35 -0
  187. data/spec/public/check_spec.rb +191 -0
  188. data/spec/public/choose_spec.rb +118 -0
  189. data/spec/public/click_area_spec.rb +106 -0
  190. data/spec/public/click_button_spec.rb +494 -0
  191. data/spec/public/click_link_spec.rb +544 -0
  192. data/spec/public/fill_in_spec.rb +224 -0
  193. data/spec/public/locators/field_by_xpath_spec.rb +19 -0
  194. data/spec/public/locators/field_labeled_spec.rb +172 -0
  195. data/spec/public/locators/field_with_id_spec.rb +16 -0
  196. data/spec/public/matchers/contain_spec.rb +107 -0
  197. data/spec/public/matchers/have_selector_spec.rb +146 -0
  198. data/spec/public/matchers/have_tag_spec.rb +39 -0
  199. data/spec/public/matchers/have_xpath_spec.rb +142 -0
  200. data/spec/public/reload_spec.rb +10 -0
  201. data/spec/public/save_and_open_spec.rb +49 -0
  202. data/spec/public/select_date_spec.rb +112 -0
  203. data/spec/public/select_datetime_spec.rb +137 -0
  204. data/spec/public/select_spec.rb +474 -0
  205. data/spec/public/select_time_spec.rb +100 -0
  206. data/spec/public/selenium/application_server_factory_spec.rb +49 -0
  207. data/spec/public/selenium/application_servers/external_spec.rb +12 -0
  208. data/spec/public/selenium/selenium_session_spec.rb +37 -0
  209. data/spec/public/set_hidden_field_spec.rb +5 -0
  210. data/spec/public/submit_form_spec.rb +56 -0
  211. data/spec/public/visit_spec.rb +58 -0
  212. data/spec/public/within_spec.rb +177 -0
  213. data/spec/rcov.opts +1 -0
  214. data/spec/spec.opts +2 -0
  215. data/spec/spec_helper.rb +53 -0
  216. data/vendor/selenium-server.jar +0 -0
  217. data/webrat.gemspec +355 -0
  218. metadata +417 -0
@@ -0,0 +1,11 @@
1
+ require "webrat/integrations/merb"
2
+
3
+ module Webrat
4
+ class MerbAdapter < RackAdapter #:nodoc:
5
+ def initialize(context=nil)
6
+ app = context.respond_to?(:app) ?
7
+ context.app : Merb::Rack::Application.new
8
+ super(Rack::Test::Session.new(Rack::MockSession.new(app, "www.example.com")))
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ require "rack/test"
2
+
3
+ module Webrat
4
+ class RackAdapter
5
+ extend Forwardable
6
+
7
+ def_delegators :@session, :get, :post, :put, :delete
8
+
9
+ def initialize(session) #:nodoc:
10
+ @session = session
11
+ end
12
+
13
+ def response_body
14
+ response.body
15
+ end
16
+
17
+ def response_code
18
+ response.status
19
+ end
20
+
21
+ def response_headers
22
+ response.headers
23
+ end
24
+
25
+ def response
26
+ @session.last_response
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,77 @@
1
+ require "webrat/integrations/rails"
2
+ require "action_controller/record_identifier"
3
+
4
+ module Webrat
5
+ class RailsAdapter #:nodoc:
6
+ include ActionController::RecordIdentifier
7
+
8
+ attr_reader :integration_session
9
+
10
+ def initialize(session)
11
+ @integration_session = session
12
+ end
13
+
14
+ def get(url, data, headers = nil)
15
+ do_request(:get, url, data, headers)
16
+ end
17
+
18
+ def post(url, data, headers = nil)
19
+ do_request(:post, url, data, headers)
20
+ end
21
+
22
+ def put(url, data, headers = nil)
23
+ do_request(:put, url, data, headers)
24
+ end
25
+
26
+ def delete(url, data, headers = nil)
27
+ do_request(:delete, url, data, headers)
28
+ end
29
+
30
+ def response_body
31
+ response.body
32
+ end
33
+
34
+ def response_code
35
+ response.code.to_i
36
+ end
37
+
38
+ def response_headers
39
+ response.headers
40
+ end
41
+
42
+ def xml_content_type?
43
+ response.headers["Content-Type"].to_s =~ /xml/
44
+ end
45
+
46
+ protected
47
+
48
+ def do_request(http_method, url, data, headers) #:nodoc:
49
+ update_protocol(url)
50
+ integration_session.send(http_method, normalize_url(url), data, headers)
51
+ end
52
+
53
+ # remove protocol, host and anchor
54
+ def normalize_url(href) #:nodoc:
55
+ uri = URI.parse(href)
56
+ normalized_url = []
57
+ normalized_url << "#{uri.scheme}://" if uri.scheme
58
+ normalized_url << uri.host if uri.host
59
+ normalized_url << ":#{uri.port}" if uri.port && ![80,443].include?(uri.port)
60
+ normalized_url << uri.path if uri.path
61
+ normalized_url << "?#{uri.query}" if uri.query
62
+ normalized_url.join
63
+ end
64
+
65
+ def update_protocol(href) #:nodoc:
66
+ if href =~ /^https:/
67
+ integration_session.https!(true)
68
+ elsif href =~ /^http:/
69
+ integration_session.https!(false)
70
+ end
71
+ end
72
+
73
+ def response #:nodoc:
74
+ integration_session.response
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,9 @@
1
+ module Webrat
2
+ class SinatraAdapter < RackAdapter
3
+ def initialize(context)
4
+ app = context.respond_to?(:app) ? context.app : Sinatra::Application
5
+
6
+ super(Rack::Test::Session.new(Rack::MockSession.new(app, "www.example.com")))
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ require "webrat/core/configuration"
2
+ require "webrat/core/xml"
3
+ require "webrat/core/logging"
4
+ require "webrat/core/elements/form"
5
+ require "webrat/core/scope"
6
+ require "webrat/core/elements/link"
7
+ require "webrat/core/elements/area"
8
+ require "webrat/core/elements/label"
9
+ require "webrat/core/elements/select_option"
10
+ require "webrat/core/session"
11
+ require "webrat/core/methods"
12
+ require "webrat/core/matchers"
13
+ require "webrat/core/save_and_open_page"
@@ -0,0 +1,114 @@
1
+ require "webrat/core_extensions/deprecate"
2
+ require "pathname"
3
+
4
+ module Webrat
5
+
6
+ # Configures Webrat. If this is not done, Webrat will be created
7
+ # with all of the default settings.
8
+ def self.configure(configuration = Webrat.configuration)
9
+ yield configuration if block_given?
10
+ @@configuration = configuration
11
+ end
12
+
13
+ def self.configuration # :nodoc:
14
+ @@configuration ||= Webrat::Configuration.new
15
+ end
16
+
17
+ # Webrat can be configured using the Webrat.configure method. For example:
18
+ #
19
+ # Webrat.configure do |config|
20
+ # config.mode = :sinatra
21
+ # end
22
+ class Configuration
23
+
24
+ # Webrat's mode, set automatically when requiring webrat/rails, webrat/merb, etc.
25
+ attr_reader :mode # :nodoc:
26
+
27
+ # Save and open pages with error status codes (500-599) in a browser? Defualts to true.
28
+ attr_writer :open_error_files
29
+
30
+ # Save and open page storage directory, defaults to "tmp" under current directory if exists, otherwise current directory
31
+ attr_accessor :saved_pages_dir
32
+
33
+ # Which rails environment should the selenium tests be run in? Defaults to test.
34
+ attr_accessor :application_environment
35
+ webrat_deprecate :selenium_environment, :application_environment
36
+ webrat_deprecate :selenium_environment=, :application_environment=
37
+
38
+ # Which port is the application running on for selenium testing? Defaults to 3001.
39
+ attr_accessor :application_port
40
+ webrat_deprecate :selenium_port, :application_port
41
+ webrat_deprecate :selenium_port=, :application_port=
42
+
43
+ # Which port should selenium use to access the application. Defaults to application_port
44
+ attr_writer :application_port_for_selenium
45
+
46
+ def application_port_for_selenium
47
+ @application_port_for_selenium || self.application_port
48
+ end
49
+
50
+ # Which underlying app framework we're testing with selenium
51
+ attr_accessor :application_framework
52
+
53
+ # Which server the application is running on for selenium testing? Defaults to localhost
54
+ attr_accessor :application_address
55
+
56
+ # Which server Selenium server is running on. Defaults to nil(server starts in webrat process and runs locally)
57
+ attr_accessor :selenium_server_address
58
+
59
+ # Which server Selenium port is running on. Defaults to 4444
60
+ attr_accessor :selenium_server_port
61
+
62
+ # Set the key that Selenium uses to determine the browser running. Default *firefox
63
+ attr_accessor :selenium_browser_key
64
+
65
+ # Set the timeout for waiting for the browser process to start
66
+ attr_accessor :selenium_browser_startup_timeout
67
+
68
+ # Set the firefox profile for selenium to use
69
+ attr_accessor :selenium_firefox_profile
70
+
71
+ # How many redirects to the same URL should be halted as an infinite redirect
72
+ # loop? Defaults to 10
73
+ attr_accessor :infinite_redirect_limit
74
+
75
+ # Print out the full HTML on wait failure
76
+ # Defaults to false
77
+ attr_accessor :selenium_verbose_output
78
+
79
+ def initialize # :nodoc:
80
+ self.open_error_files = true
81
+ self.application_environment = :test
82
+ self.application_port = 3001
83
+ self.application_address = 'localhost'
84
+ self.application_framework = :rails
85
+ self.selenium_server_port = 4444
86
+ self.infinite_redirect_limit = 10
87
+ self.selenium_browser_key = '*firefox'
88
+ self.selenium_browser_startup_timeout = 5
89
+ self.selenium_verbose_output = false
90
+
91
+ tmp_dir = Pathname.new(Dir.pwd).join("tmp")
92
+ self.saved_pages_dir = tmp_dir.exist? ? tmp_dir : Dir.pwd
93
+ end
94
+
95
+ def open_error_files? #:nodoc:
96
+ @open_error_files ? true : false
97
+ end
98
+
99
+ # Allows setting of webrat's mode, valid modes are:
100
+ # :rails, :selenium, :rack, :sinatra, :mechanize, :merb
101
+ def mode=(mode)
102
+ @mode = mode.to_sym
103
+
104
+ begin
105
+ require("webrat/integrations/#{mode}")
106
+ rescue LoadError
107
+ # Only some modes have integration code that needs to
108
+ # be loaded, so this is OK
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ end
@@ -0,0 +1,31 @@
1
+ require "webrat/core/elements/element"
2
+
3
+ module Webrat
4
+ class Area < Element #:nodoc:
5
+
6
+ def self.xpath_search
7
+ [".//area"]
8
+ end
9
+
10
+ def click(method = nil, options = {})
11
+ @session.request_page(absolute_href, :get, {})
12
+ end
13
+
14
+ protected
15
+
16
+ def href
17
+ @element["href"]
18
+ end
19
+
20
+ def absolute_href
21
+ if href =~ /^\?/
22
+ "#{@session.current_url}#{href}"
23
+ elsif href !~ %r{^https?://[\w|.]+(/.*)} && (href !~ /^\//)
24
+ "#{@session.current_url}/#{href}"
25
+ else
26
+ href
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ module Webrat
2
+
3
+ class Element # :nodoc:
4
+
5
+ def self.load_all(session, dom)
6
+ dom.xpath(*xpath_search).map do |element|
7
+ load(session, element)
8
+ end
9
+ end
10
+
11
+ def self.load(session, element)
12
+ return nil if element.nil?
13
+ session.elements[element.path] ||= self.new(session, element)
14
+ end
15
+
16
+ attr_reader :element
17
+
18
+ def initialize(session, element)
19
+ @session = session
20
+ @element = element
21
+ end
22
+
23
+ def path
24
+ @element.path
25
+ end
26
+
27
+ def inspect
28
+ "#<#{self.class} @element=#{element.inspect}>"
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,438 @@
1
+ require "cgi"
2
+ require "digest/md5"
3
+ require "webrat/core_extensions/blank"
4
+ require "webrat/core_extensions/nil_to_query_string"
5
+
6
+ require "webrat/core/elements/element"
7
+
8
+ module Webrat
9
+ # Raised when Webrat is asked to manipulate a disabled form field
10
+ class DisabledFieldError < WebratError
11
+ end
12
+
13
+ class Field < Element #:nodoc:
14
+ attr_reader :value
15
+
16
+ def self.xpath_search
17
+ ".//button|.//input|.//textarea|.//select"
18
+ end
19
+
20
+ def self.xpath_search_excluding_hidden
21
+ [".//button", ".//input[ @type != 'hidden']", ".//textarea", ".//select"]
22
+ end
23
+
24
+ def self.field_classes
25
+ @field_classes || []
26
+ end
27
+
28
+ def self.inherited(klass)
29
+ @field_classes ||= []
30
+ @field_classes << klass
31
+ # raise args.inspect
32
+ end
33
+
34
+ def self.load(session, element)
35
+ return nil if element.nil?
36
+ session.elements[element.path] ||= field_class(element).new(session, element)
37
+ end
38
+
39
+ def self.field_class(element)
40
+ case element.name
41
+ when "button" then ButtonField
42
+ when "select"
43
+ if element.attributes["multiple"].nil?
44
+ SelectField
45
+ else
46
+ MultipleSelectField
47
+ end
48
+ when "textarea" then TextareaField
49
+ else
50
+ case element["type"]
51
+ when "checkbox" then CheckboxField
52
+ when "hidden" then HiddenField
53
+ when "radio" then RadioField
54
+ when "password" then PasswordField
55
+ when "file" then FileField
56
+ when "reset" then ResetField
57
+ when "submit" then ButtonField
58
+ when "button" then ButtonField
59
+ when "image" then ButtonField
60
+ else TextField
61
+ end
62
+ end
63
+ end
64
+
65
+ def initialize(*args)
66
+ super
67
+ @value = default_value
68
+ end
69
+
70
+ def label_text
71
+ return nil if labels.empty?
72
+ labels.first.text
73
+ end
74
+
75
+ def id
76
+ @element["id"]
77
+ end
78
+
79
+ def disabled?
80
+ @element.attributes.has_key?("disabled") && @element["disabled"] != 'false'
81
+ end
82
+
83
+ def raise_error_if_disabled
84
+ return unless disabled?
85
+ raise DisabledFieldError.new("Cannot interact with disabled form element (#{self})")
86
+ end
87
+
88
+ def to_query_string
89
+ return nil if disabled?
90
+
91
+ query_string = case Webrat.configuration.mode
92
+ when :rails, :merb, :rack, :sinatra
93
+ build_query_string
94
+ when :mechanize
95
+ build_query_string(false)
96
+ end
97
+
98
+ query_string
99
+ end
100
+
101
+ def set(value)
102
+ @value = value
103
+ end
104
+
105
+ def unset
106
+ @value = default_value
107
+ end
108
+
109
+ protected
110
+
111
+ def form
112
+ Form.load(@session, form_element)
113
+ end
114
+
115
+ def form_element
116
+ parent = @element.parent
117
+
118
+ while parent.respond_to?(:parent)
119
+ return parent if parent.name == 'form'
120
+ parent = parent.parent
121
+ end
122
+ end
123
+
124
+ def name
125
+ @element["name"]
126
+ end
127
+
128
+ def build_query_string(escape_value=true)
129
+ if @value.is_a?(Array)
130
+ @value.collect {|value| "#{name}=#{ escape_value ? escape(value) : value }" }.join("&")
131
+ else
132
+ "#{name}=#{ escape_value ? escape(value) : value }"
133
+ end
134
+ end
135
+
136
+ def escape(value)
137
+ CGI.escape(value.to_s)
138
+ end
139
+
140
+ def escaped_value
141
+ CGI.escape(@value.to_s)
142
+ end
143
+
144
+ def labels
145
+ @labels ||= label_elements.map do |element|
146
+ Label.load(@session, element)
147
+ end
148
+ end
149
+
150
+ def label_elements
151
+ return @label_elements unless @label_elements.nil?
152
+ @label_elements = []
153
+
154
+ parent = @element.parent
155
+ while parent.respond_to?(:parent)
156
+ if parent.name == 'label'
157
+ @label_elements.push parent
158
+ break
159
+ end
160
+ parent = parent.parent
161
+ end
162
+
163
+ unless id.blank?
164
+ @label_elements += form.element.xpath(".//label[@for = '#{id}']")
165
+ end
166
+
167
+ @label_elements
168
+ end
169
+
170
+ def default_value
171
+ @element["value"]
172
+ end
173
+ end
174
+
175
+ class ButtonField < Field #:nodoc:
176
+
177
+ def self.xpath_search
178
+ [".//button", ".//input[@type = 'submit']", ".//input[@type = 'button']", ".//input[@type = 'image']"]
179
+ end
180
+
181
+ def to_query_string
182
+ return nil if @value.nil?
183
+ super
184
+ end
185
+
186
+ def default_value
187
+ nil
188
+ end
189
+
190
+ def click
191
+ raise_error_if_disabled
192
+ set(@element["value"]) unless @element["name"].blank?
193
+ form.submit
194
+ end
195
+
196
+ end
197
+
198
+ class HiddenField < Field #:nodoc:
199
+
200
+ def self.xpath_search
201
+ ".//input[@type = 'hidden']"
202
+ end
203
+
204
+ def to_query_string
205
+ if collection_name?
206
+ super
207
+ else
208
+ checkbox_with_same_name = form.field_named(name, CheckboxField)
209
+
210
+ if checkbox_with_same_name.to_query_string.blank?
211
+ super
212
+ else
213
+ nil
214
+ end
215
+ end
216
+ end
217
+
218
+ protected
219
+
220
+ def collection_name?
221
+ name =~ /\[\]/
222
+ end
223
+
224
+ end
225
+
226
+ class CheckboxField < Field #:nodoc:
227
+
228
+ def self.xpath_search
229
+ ".//input[@type = 'checkbox']"
230
+ end
231
+
232
+ def to_query_string
233
+ return nil if @value.nil?
234
+ super
235
+ end
236
+
237
+ def check
238
+ raise_error_if_disabled
239
+ set(@element["value"] || "on")
240
+ end
241
+
242
+ def checked?
243
+ @element["checked"] == "checked"
244
+ end
245
+
246
+ def uncheck
247
+ raise_error_if_disabled
248
+ set(nil)
249
+ end
250
+
251
+ protected
252
+
253
+ def default_value
254
+ if @element["checked"] == "checked"
255
+ @element["value"] || "on"
256
+ else
257
+ nil
258
+ end
259
+ end
260
+
261
+ end
262
+
263
+ class PasswordField < Field #:nodoc:
264
+
265
+ def self.xpath_search
266
+ ".//input[@type = 'password']"
267
+ end
268
+
269
+ end
270
+
271
+ class RadioField < Field #:nodoc:
272
+
273
+ def self.xpath_search
274
+ ".//input[@type = 'radio']"
275
+ end
276
+
277
+ def to_query_string
278
+ return nil if @value.nil?
279
+ super
280
+ end
281
+
282
+ def choose
283
+ raise_error_if_disabled
284
+ other_options.each do |option|
285
+ option.set(nil)
286
+ end
287
+
288
+ set(@element["value"] || "on")
289
+ end
290
+
291
+ def checked?
292
+ @element["checked"] == "checked"
293
+ end
294
+
295
+ protected
296
+
297
+ def other_options
298
+ form.fields.select { |f| f.name == name }
299
+ end
300
+
301
+ def default_value
302
+ if @element["checked"] == "checked"
303
+ @element["value"] || "on"
304
+ else
305
+ nil
306
+ end
307
+ end
308
+
309
+ end
310
+
311
+ class TextareaField < Field #:nodoc:
312
+
313
+ def self.xpath_search
314
+ ".//textarea"
315
+ end
316
+
317
+ protected
318
+
319
+ def default_value
320
+ @element.inner_html
321
+ end
322
+
323
+ end
324
+
325
+ class FileField < Field #:nodoc:
326
+
327
+ def self.xpath_search
328
+ ".//input[@type = 'file']"
329
+ end
330
+
331
+ attr_accessor :content_type
332
+
333
+ def set(value, content_type = nil)
334
+ @original_value = @value
335
+ @content_type ||= content_type
336
+ super(value)
337
+ end
338
+
339
+ def digest_value
340
+ @value ? Digest::MD5.hexdigest(self.object_id.to_s) : ""
341
+ end
342
+
343
+ def to_query_string
344
+ @value.nil? ? set("") : set(digest_value)
345
+ super
346
+ end
347
+
348
+ def test_uploaded_file
349
+ return "" if @original_value.blank?
350
+
351
+ case Webrat.configuration.mode
352
+ when :rails
353
+ if content_type
354
+ ActionController::TestUploadedFile.new(@original_value, content_type)
355
+ else
356
+ ActionController::TestUploadedFile.new(@original_value)
357
+ end
358
+ when :rack, :merb
359
+ Rack::Test::UploadedFile.new(@original_value, content_type)
360
+ end
361
+ end
362
+
363
+ end
364
+
365
+ class TextField < Field #:nodoc:
366
+ def self.xpath_search
367
+ [".//input[@type = 'text']", ".//input[not(@type)]"]
368
+ end
369
+ end
370
+
371
+ class ResetField < Field #:nodoc:
372
+ def self.xpath_search
373
+ [".//input[@type = 'reset']"]
374
+ end
375
+ end
376
+
377
+ class SelectField < Field #:nodoc:
378
+
379
+ def self.xpath_search
380
+ [".//select[not(@multiple)]"]
381
+ end
382
+
383
+ def options
384
+ @options ||= SelectOption.load_all(@session, @element)
385
+ end
386
+
387
+ def unset(value)
388
+ @value = nil
389
+ end
390
+
391
+ protected
392
+
393
+ def default_value
394
+ selected_options = @element.xpath(".//option[@selected = 'selected']")
395
+ selected_options = @element.xpath(".//option[position() = 1]") if selected_options.empty?
396
+
397
+ selected_options.map do |option|
398
+ return "" if option.nil?
399
+ option["value"] || option.inner_html
400
+ end.uniq.first
401
+ end
402
+
403
+ end
404
+
405
+ class MultipleSelectField < Field #:nodoc:
406
+
407
+ def self.xpath_search
408
+ [".//select[@multiple='multiple']"]
409
+ end
410
+
411
+ def options
412
+ @options ||= SelectOption.load_all(@session, @element)
413
+ end
414
+
415
+ def set(value)
416
+ @value << value
417
+ end
418
+
419
+ def unset(value)
420
+ @value.delete(value)
421
+ end
422
+
423
+ protected
424
+
425
+ # Overwrite SelectField definition because we don't want to select the first option
426
+ # (mutliples don't select the first option unlike their non multiple versions)
427
+ def default_value
428
+ selected_options = @element.xpath(".//option[@selected = 'selected']")
429
+
430
+ selected_options.map do |option|
431
+ return "" if option.nil?
432
+ option["value"] || option.inner_html
433
+ end.uniq
434
+ end
435
+
436
+ end
437
+
438
+ end