webrat 0.3.4 → 0.4.0

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 (63) hide show
  1. data/History.txt +140 -30
  2. data/README.rdoc +85 -0
  3. data/Rakefile +72 -22
  4. data/install.rb +1 -1
  5. data/lib/webrat.rb +12 -17
  6. data/lib/webrat/core.rb +9 -7
  7. data/lib/webrat/core/configuration.rb +87 -0
  8. data/lib/webrat/core/{area.rb → elements/area.rb} +7 -20
  9. data/lib/webrat/core/elements/element.rb +33 -0
  10. data/lib/webrat/core/elements/field.rb +394 -0
  11. data/lib/webrat/core/elements/form.rb +103 -0
  12. data/lib/webrat/core/elements/label.rb +31 -0
  13. data/lib/webrat/core/{link.rb → elements/link.rb} +15 -26
  14. data/lib/webrat/core/elements/select_option.rb +35 -0
  15. data/lib/webrat/core/locators.rb +13 -85
  16. data/lib/webrat/core/locators/area_locator.rb +38 -0
  17. data/lib/webrat/core/locators/button_locator.rb +54 -0
  18. data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
  19. data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
  20. data/lib/webrat/core/locators/field_locator.rb +25 -0
  21. data/lib/webrat/core/locators/field_named_locator.rb +41 -0
  22. data/lib/webrat/core/locators/form_locator.rb +19 -0
  23. data/lib/webrat/core/locators/label_locator.rb +34 -0
  24. data/lib/webrat/core/locators/link_locator.rb +66 -0
  25. data/lib/webrat/core/locators/locator.rb +20 -0
  26. data/lib/webrat/core/locators/select_option_locator.rb +59 -0
  27. data/lib/webrat/core/logging.rb +5 -9
  28. data/lib/webrat/core/matchers/have_content.rb +19 -44
  29. data/lib/webrat/core/matchers/have_selector.rb +15 -2
  30. data/lib/webrat/core/matchers/have_tag.rb +15 -2
  31. data/lib/webrat/core/matchers/have_xpath.rb +21 -28
  32. data/lib/webrat/core/methods.rb +32 -15
  33. data/lib/webrat/core/mime.rb +3 -3
  34. data/lib/webrat/core/save_and_open_page.rb +50 -0
  35. data/lib/webrat/core/scope.rb +183 -41
  36. data/lib/webrat/core/session.rb +125 -63
  37. data/lib/webrat/core/xml.rb +115 -0
  38. data/lib/webrat/core/xml/hpricot.rb +19 -0
  39. data/lib/webrat/core/xml/nokogiri.rb +76 -0
  40. data/lib/webrat/core/xml/rexml.rb +24 -0
  41. data/lib/webrat/core_extensions/deprecate.rb +1 -1
  42. data/lib/webrat/mechanize.rb +58 -12
  43. data/lib/webrat/merb.rb +7 -73
  44. data/lib/webrat/merb_session.rb +65 -0
  45. data/lib/webrat/rack.rb +1 -1
  46. data/lib/webrat/rails.rb +56 -55
  47. data/lib/webrat/rspec-rails.rb +13 -0
  48. data/lib/webrat/selenium.rb +92 -1
  49. data/lib/webrat/selenium/matchers.rb +146 -0
  50. data/lib/webrat/selenium/selenium_session.rb +179 -80
  51. data/lib/webrat/sinatra.rb +14 -4
  52. data/vendor/selenium-server.jar +0 -0
  53. metadata +36 -17
  54. data/README.txt +0 -90
  55. data/TODO.txt +0 -10
  56. data/init.rb +0 -3
  57. data/lib/webrat/core/field.rb +0 -332
  58. data/lib/webrat/core/flunk.rb +0 -7
  59. data/lib/webrat/core/form.rb +0 -130
  60. data/lib/webrat/core/label.rb +0 -18
  61. data/lib/webrat/core/nokogiri.rb +0 -44
  62. data/lib/webrat/core/select_option.rb +0 -29
  63. data/lib/webrat/rails/redirect_actions.rb +0 -18
@@ -2,43 +2,66 @@ require "forwardable"
2
2
  require "ostruct"
3
3
 
4
4
  require "webrat/core/mime"
5
+ require "webrat/core/save_and_open_page"
5
6
 
6
7
  module Webrat
8
+ # A page load or form submission returned an unsuccessful response code (500-599)
9
+ class PageLoadError < WebratError
10
+ end
11
+
12
+ def self.session_class
13
+ case Webrat.configuration.mode
14
+ when :rails
15
+ RailsSession
16
+ when :merb
17
+ MerbSession
18
+ when :selenium
19
+ SeleniumSession
20
+ when :rack
21
+ RackSession
22
+ when :sinatra
23
+ SinatraSession
24
+ when :mechanize
25
+ MechanizeSession
26
+ else
27
+ raise WebratError.new(<<-STR)
28
+ Unknown Webrat mode: #{Webrat.configuration.mode.inspect}
29
+
30
+ Please ensure you have a Webrat configuration block that specifies a mode
31
+ in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
32
+
33
+ This configure block supercedes the need to require "webrat/<framework>".
34
+
35
+ For example:
36
+
37
+ Webrat.configure do |config|
38
+ config.mode = :rails
39
+ end
40
+ STR
41
+ end
42
+ end
43
+
7
44
  class Session
8
45
  extend Forwardable
9
46
  include Logging
10
- include Flunk
11
-
47
+ include SaveAndOpenPage
12
48
  attr_reader :current_url
13
-
14
- def initialize #:nodoc:
49
+ attr_reader :elements
50
+
51
+ def initialize(context = nil) #:nodoc:
15
52
  @http_method = :get
16
53
  @data = {}
17
54
  @default_headers = {}
18
55
  @custom_headers = {}
19
- end
56
+ @context = context
20
57
 
21
- # Saves the page out to RAILS_ROOT/tmp/ and opens it in the default
22
- # web browser if on OS X. Useful for debugging.
23
- #
24
- # Example:
25
- # save_and_open_page
26
- def save_and_open_page
27
- return unless File.exist?(saved_page_dir)
28
-
29
- filename = "#{saved_page_dir}/webrat-#{Time.now.to_i}.html"
30
-
31
- File.open(filename, "w") do |f|
32
- f.write rewrite_css_and_image_references(response_body)
33
- end
34
-
35
- open_in_browser(filename)
58
+ reset
36
59
  end
37
-
60
+
38
61
  def current_dom #:nodoc:
39
62
  current_scope.dom
40
63
  end
41
-
64
+
42
65
  # For backwards compatibility -- removing in 1.0
43
66
  def current_page #:nodoc:
44
67
  page = OpenStruct.new
@@ -47,15 +70,11 @@ module Webrat
47
70
  page.data = @data
48
71
  page
49
72
  end
50
-
73
+
51
74
  def doc_root #:nodoc:
52
75
  nil
53
76
  end
54
77
 
55
- def saved_page_dir #:nodoc:
56
- File.expand_path(".")
57
- end
58
-
59
78
  def header(key, value)
60
79
  @custom_headers[key] = value
61
80
  end
@@ -63,7 +82,7 @@ module Webrat
63
82
  def http_accept(mime_type)
64
83
  header('Accept', Webrat::MIME.mime_type(mime_type))
65
84
  end
66
-
85
+
67
86
  def basic_auth(user, pass)
68
87
  encoded_login = ["#{user}:#{pass}"].pack("m*")
69
88
  header('HTTP_AUTHORIZATION', "Basic #{encoded_login}")
@@ -84,44 +103,51 @@ module Webrat
84
103
  send "#{http_method}", url, data || {}, h
85
104
  end
86
105
 
87
- save_and_open_page if exception_caught?
88
- flunk("Page load was not successful (Code: #{response_code.inspect}):\n#{formatted_error}") unless success_code?
89
-
90
- @_scopes = nil
91
- @_page_scope = nil
106
+ save_and_open_page if exception_caught? && Webrat.configuration.open_error_files?
107
+ raise PageLoadError.new("Page load was not successful (Code: #{response_code.inspect}):\n#{formatted_error}") unless success_code?
108
+
109
+ reset
110
+
92
111
  @current_url = url
93
112
  @http_method = http_method
94
113
  @data = data
95
-
114
+
115
+ request_page(response_location, :get, data) if internal_redirect?
116
+
96
117
  return response
97
118
  end
98
-
119
+
99
120
  def success_code? #:nodoc:
100
121
  (200..499).include?(response_code)
101
122
  end
102
-
123
+
124
+ def redirect? #:nodoc:
125
+ response_code / 100 == 3
126
+ end
127
+
128
+ def internal_redirect? #:nodoc:
129
+ redirect? && current_host == response_location_host
130
+ end
131
+
103
132
  def exception_caught? #:nodoc:
104
133
  response_body =~ /Exception caught/
105
134
  end
106
-
135
+
107
136
  def current_scope #:nodoc:
108
137
  scopes.last || page_scope
109
138
  end
110
-
139
+
111
140
  # Reloads the last page requested. Note that this will resubmit forms
112
141
  # and their data.
113
- #
114
- # Example:
115
- # reloads
116
- def reloads
142
+ def reload
117
143
  request_page(@current_url, @http_method, @data)
118
144
  end
119
145
 
120
- alias_method :reload, :reloads
121
-
122
-
146
+ webrat_deprecate :reloads, :reload
147
+
148
+
123
149
  # Works like click_link, but only looks for the link text within a given selector
124
- #
150
+ #
125
151
  # Example:
126
152
  # click_link_within "#user_12", "Vote"
127
153
  def click_link_within(selector, link_text)
@@ -130,15 +156,15 @@ module Webrat
130
156
  end
131
157
  end
132
158
 
133
- alias_method :clicks_link_within, :click_link_within
134
-
159
+ webrat_deprecate :clicks_link_within, :click_link_within
160
+
135
161
  def within(selector)
136
162
  scopes.push(Scope.from_scope(self, current_scope, selector))
137
163
  ret = yield(current_scope)
138
164
  scopes.pop
139
165
  return ret
140
166
  end
141
-
167
+
142
168
  # Issues a GET request for a page, follows any redirects, and verifies the final page
143
169
  # load was successful.
144
170
  #
@@ -147,17 +173,8 @@ module Webrat
147
173
  def visit(url = nil, http_method = :get, data = {})
148
174
  request_page(url, http_method, data)
149
175
  end
150
-
151
- alias_method :visits, :visit
152
-
153
- def open_in_browser(path) #:nodoc
154
- `open #{path}`
155
- end
156
-
157
- def rewrite_css_and_image_references(response_html) #:nodoc
158
- return response_html unless doc_root
159
- response_html.gsub(/"\/(stylesheets|images)/, doc_root + '/\1')
160
- end
176
+
177
+ webrat_deprecate :visits, :visit
161
178
 
162
179
  # Subclasses can override this to show error messages without html
163
180
  def formatted_error #:nodoc:
@@ -171,18 +188,63 @@ module Webrat
171
188
  def page_scope #:nodoc:
172
189
  @_page_scope ||= Scope.from_page(self, response, response_body)
173
190
  end
174
-
191
+
192
+ def dom
193
+ page_scope.dom
194
+ end
195
+
196
+ def xml_content_type?
197
+ false
198
+ end
199
+
200
+ def simulate
201
+ return if Webrat.configuration.mode == :selenium
202
+ yield
203
+ end
204
+
205
+ def automate
206
+ return unless Webrat.configuration.mode == :selenium
207
+ yield
208
+ end
209
+
175
210
  def_delegators :current_scope, :fill_in, :fills_in
211
+ def_delegators :current_scope, :set_hidden_field
212
+ def_delegators :current_scope, :submit_form
176
213
  def_delegators :current_scope, :check, :checks
177
214
  def_delegators :current_scope, :uncheck, :unchecks
178
215
  def_delegators :current_scope, :choose, :chooses
179
216
  def_delegators :current_scope, :select, :selects
217
+ def_delegators :current_scope, :select_datetime, :selects_datetime
218
+ def_delegators :current_scope, :select_date, :selects_date
219
+ def_delegators :current_scope, :select_time, :selects_time
180
220
  def_delegators :current_scope, :attach_file, :attaches_file
181
221
  def_delegators :current_scope, :click_area, :clicks_area
182
222
  def_delegators :current_scope, :click_link, :clicks_link
183
223
  def_delegators :current_scope, :click_button, :clicks_button
184
- def_delegators :current_scope, :should_see
185
- def_delegators :current_scope, :should_not_see
186
224
  def_delegators :current_scope, :field_labeled
225
+ def_delegators :current_scope, :field_by_xpath
226
+ def_delegators :current_scope, :field_with_id
227
+ def_delegators :current_scope, :select_option
228
+
229
+ private
230
+
231
+ def response_location
232
+ response.headers["Location"]
233
+ end
234
+
235
+ def current_host
236
+ URI.parse(current_url).host || "www.example.com"
237
+ end
238
+
239
+ def response_location_host
240
+ URI.parse(response_location).host || "www.example.com"
241
+ end
242
+
243
+ def reset
244
+ @elements = {}
245
+ @_scopes = nil
246
+ @_page_scope = nil
247
+ end
248
+
187
249
  end
188
250
  end
@@ -0,0 +1,115 @@
1
+ require "webrat/core/xml/nokogiri"
2
+ require "webrat/core/xml/hpricot"
3
+ require "webrat/core/xml/rexml"
4
+
5
+ module Webrat #:nodoc:
6
+ module XML #:nodoc:
7
+
8
+ def self.document(stringlike) #:nodoc:
9
+ if Webrat.configuration.parse_with_nokogiri?
10
+ Webrat.nokogiri_document(stringlike)
11
+ else
12
+ Webrat.rexml_document(Webrat.hpricot_document(stringlike).to_html)
13
+ end
14
+ end
15
+
16
+ def self.html_document(stringlike) #:nodoc:
17
+ if Webrat.configuration.parse_with_nokogiri?
18
+ Webrat.html_nokogiri_document(stringlike)
19
+ else
20
+ Webrat.rexml_document(Webrat.hpricot_document(stringlike).to_html)
21
+ end
22
+ end
23
+
24
+ def self.xml_document(stringlike) #:nodoc:
25
+ if Webrat.configuration.parse_with_nokogiri?
26
+ Webrat.xml_nokogiri_document(stringlike)
27
+ else
28
+ Webrat.rexml_document(Webrat.hpricot_document(stringlike).to_html)
29
+ end
30
+ end
31
+
32
+ def self.to_html(element)
33
+ if Webrat.configuration.parse_with_nokogiri?
34
+ element.to_html
35
+ else
36
+ element.to_s
37
+ end
38
+ end
39
+
40
+ def self.inner_html(element)
41
+ if Webrat.configuration.parse_with_nokogiri?
42
+ element.inner_html
43
+ else
44
+ element.text
45
+ end
46
+ end
47
+
48
+ def self.all_inner_text(element)
49
+ if Webrat.configuration.parse_with_nokogiri?
50
+ element.inner_text
51
+ else
52
+ Hpricot(element.to_s).children.first.inner_text
53
+ end
54
+ end
55
+
56
+ def self.inner_text(element)
57
+ if Webrat.configuration.parse_with_nokogiri?
58
+ element.inner_text
59
+ else
60
+ if defined?(Hpricot::Doc) && element.is_a?(Hpricot::Doc)
61
+ element.inner_text
62
+ else
63
+ element.text
64
+ end
65
+ end
66
+ end
67
+
68
+ def self.xpath_to(element)
69
+ if Webrat.configuration.parse_with_nokogiri?
70
+ element.path
71
+ else
72
+ element.xpath
73
+ end
74
+ end
75
+
76
+ def self.attribute(element, attribute_name)
77
+ return element[attribute_name] if element.is_a?(Hash)
78
+
79
+ if Webrat.configuration.parse_with_nokogiri?
80
+ element[attribute_name]
81
+ else
82
+ element.attributes[attribute_name]
83
+ end
84
+ end
85
+
86
+ def self.xpath_at(*args)
87
+ xpath_search(*args).first
88
+ end
89
+
90
+ def self.css_at(*args)
91
+ css_search(*args).first
92
+ end
93
+
94
+ def self.xpath_search(element, *searches)
95
+ searches.flatten.map do |search|
96
+ if Webrat.configuration.parse_with_nokogiri?
97
+ element.xpath(search)
98
+ else
99
+ REXML::XPath.match(element, search)
100
+ end
101
+ end.flatten.compact
102
+ end
103
+
104
+ def self.css_search(element, *searches) #:nodoc:
105
+ xpath_search(element, css_to_xpath(*searches))
106
+ end
107
+
108
+ def self.css_to_xpath(*selectors)
109
+ selectors.map do |rule|
110
+ Nokogiri::CSS.xpath_for(rule, :prefix => ".//")
111
+ end.flatten.uniq
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,19 @@
1
+ module Webrat
2
+
3
+ def self.hpricot_document(stringlike)
4
+ return stringlike.dom if stringlike.respond_to?(:dom)
5
+
6
+ if Hpricot::Doc === stringlike
7
+ stringlike
8
+ elsif Hpricot::Elements === stringlike
9
+ stringlike
10
+ elsif StringIO === stringlike
11
+ Hpricot(stringlike.string)
12
+ elsif stringlike.respond_to?(:body)
13
+ Hpricot(stringlike.body.to_s)
14
+ else
15
+ Hpricot(stringlike.to_s)
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,76 @@
1
+ require "webrat/core_extensions/meta_class"
2
+
3
+ module Webrat
4
+
5
+ def self.nokogiri_document(stringlike) #:nodoc:
6
+ return stringlike.dom if stringlike.respond_to?(:dom)
7
+
8
+ if Nokogiri::HTML::Document === stringlike
9
+ stringlike
10
+ elsif Nokogiri::XML::NodeSet === stringlike
11
+ stringlike
12
+ elsif StringIO === stringlike
13
+ Nokogiri::HTML(stringlike.string)
14
+ elsif stringlike.respond_to?(:body)
15
+ Nokogiri::HTML(stringlike.body.to_s)
16
+ else
17
+ Nokogiri::HTML(stringlike.to_s)
18
+ end
19
+ end
20
+
21
+ def self.html_nokogiri_document(stringlike) #:nodoc:
22
+ return stringlike.dom if stringlike.respond_to?(:dom)
23
+
24
+ if Nokogiri::HTML::Document === stringlike
25
+ stringlike
26
+ elsif Nokogiri::XML::NodeSet === stringlike
27
+ stringlike
28
+ elsif StringIO === stringlike
29
+ Nokogiri::HTML(stringlike.string)
30
+ elsif stringlike.respond_to?(:body)
31
+ Nokogiri::HTML(stringlike.body.to_s)
32
+ else
33
+ Nokogiri::HTML(stringlike.to_s)
34
+ end
35
+ end
36
+
37
+ def self.xml_nokogiri_document(stringlike) #:nodoc:
38
+ return stringlike.dom if stringlike.respond_to?(:dom)
39
+
40
+ if Nokogiri::HTML::Document === stringlike
41
+ stringlike
42
+ elsif Nokogiri::XML::NodeSet === stringlike
43
+ stringlike
44
+ elsif StringIO === stringlike
45
+ Nokogiri::XML(stringlike.string)
46
+ elsif stringlike.respond_to?(:body)
47
+ Nokogiri::XML(stringlike.body.to_s)
48
+ else
49
+ Nokogiri::XML(stringlike.to_s)
50
+ end
51
+ end
52
+
53
+ def self.define_dom_method(object, dom) #:nodoc:
54
+ object.meta_class.send(:define_method, :dom) do
55
+ dom
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+
62
+ module Nokogiri #:nodoc:
63
+ module CSS #:nodoc:
64
+ class XPathVisitor #:nodoc:
65
+
66
+ def visit_pseudo_class_text(node) #:nodoc:
67
+ "@type='text'"
68
+ end
69
+
70
+ def visit_pseudo_class_password(node) #:nodoc:
71
+ "@type='password'"
72
+ end
73
+
74
+ end
75
+ end
76
+ end