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.
- data/History.txt +140 -30
- data/README.rdoc +85 -0
- data/Rakefile +72 -22
- data/install.rb +1 -1
- data/lib/webrat.rb +12 -17
- data/lib/webrat/core.rb +9 -7
- data/lib/webrat/core/configuration.rb +87 -0
- data/lib/webrat/core/{area.rb → elements/area.rb} +7 -20
- data/lib/webrat/core/elements/element.rb +33 -0
- data/lib/webrat/core/elements/field.rb +394 -0
- data/lib/webrat/core/elements/form.rb +103 -0
- data/lib/webrat/core/elements/label.rb +31 -0
- data/lib/webrat/core/{link.rb → elements/link.rb} +15 -26
- data/lib/webrat/core/elements/select_option.rb +35 -0
- data/lib/webrat/core/locators.rb +13 -85
- data/lib/webrat/core/locators/area_locator.rb +38 -0
- data/lib/webrat/core/locators/button_locator.rb +54 -0
- data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
- data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
- data/lib/webrat/core/locators/field_locator.rb +25 -0
- data/lib/webrat/core/locators/field_named_locator.rb +41 -0
- data/lib/webrat/core/locators/form_locator.rb +19 -0
- data/lib/webrat/core/locators/label_locator.rb +34 -0
- data/lib/webrat/core/locators/link_locator.rb +66 -0
- data/lib/webrat/core/locators/locator.rb +20 -0
- data/lib/webrat/core/locators/select_option_locator.rb +59 -0
- data/lib/webrat/core/logging.rb +5 -9
- data/lib/webrat/core/matchers/have_content.rb +19 -44
- data/lib/webrat/core/matchers/have_selector.rb +15 -2
- data/lib/webrat/core/matchers/have_tag.rb +15 -2
- data/lib/webrat/core/matchers/have_xpath.rb +21 -28
- data/lib/webrat/core/methods.rb +32 -15
- data/lib/webrat/core/mime.rb +3 -3
- data/lib/webrat/core/save_and_open_page.rb +50 -0
- data/lib/webrat/core/scope.rb +183 -41
- data/lib/webrat/core/session.rb +125 -63
- data/lib/webrat/core/xml.rb +115 -0
- data/lib/webrat/core/xml/hpricot.rb +19 -0
- data/lib/webrat/core/xml/nokogiri.rb +76 -0
- data/lib/webrat/core/xml/rexml.rb +24 -0
- data/lib/webrat/core_extensions/deprecate.rb +1 -1
- data/lib/webrat/mechanize.rb +58 -12
- data/lib/webrat/merb.rb +7 -73
- data/lib/webrat/merb_session.rb +65 -0
- data/lib/webrat/rack.rb +1 -1
- data/lib/webrat/rails.rb +56 -55
- data/lib/webrat/rspec-rails.rb +13 -0
- data/lib/webrat/selenium.rb +92 -1
- data/lib/webrat/selenium/matchers.rb +146 -0
- data/lib/webrat/selenium/selenium_session.rb +179 -80
- data/lib/webrat/sinatra.rb +14 -4
- data/vendor/selenium-server.jar +0 -0
- metadata +36 -17
- data/README.txt +0 -90
- data/TODO.txt +0 -10
- data/init.rb +0 -3
- data/lib/webrat/core/field.rb +0 -332
- data/lib/webrat/core/flunk.rb +0 -7
- data/lib/webrat/core/form.rb +0 -130
- data/lib/webrat/core/label.rb +0 -18
- data/lib/webrat/core/nokogiri.rb +0 -44
- data/lib/webrat/core/select_option.rb +0 -29
- data/lib/webrat/rails/redirect_actions.rb +0 -18
data/lib/webrat/core/session.rb
CHANGED
@@ -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
|
11
|
-
|
47
|
+
include SaveAndOpenPage
|
12
48
|
attr_reader :current_url
|
13
|
-
|
14
|
-
|
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
|
-
|
56
|
+
@context = context
|
20
57
|
|
21
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|