indirect-webrat 0.7.4

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 (218) hide show
  1. data/.document +4 -0
  2. data/.gitignore +21 -0
  3. data/Gemfile +14 -0
  4. data/History.txt +470 -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 +30 -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 +93 -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 +85 -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 +362 -0
  47. data/lib/webrat/core/session.rb +318 -0
  48. data/lib/webrat/core/xml.rb +44 -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 +51 -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 +118 -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 +165 -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 +424 -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,30 @@
1
+ require "rack/test"
2
+
3
+ module Webrat
4
+ class RackAdapter
5
+ extend Forwardable
6
+
7
+ attr :session
8
+ def_delegators :@session, :get, :post, :put, :delete
9
+
10
+ def initialize(session) #:nodoc:
11
+ @session = session
12
+ end
13
+
14
+ def response_body
15
+ response.body
16
+ end
17
+
18
+ def response_code
19
+ response.status
20
+ end
21
+
22
+ def response_headers
23
+ response.headers
24
+ end
25
+
26
+ def response
27
+ @session.last_response
28
+ end
29
+ end
30
+ 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