-
-
Notifications
You must be signed in to change notification settings - Fork 197
/
macros.rb
266 lines (249 loc) · 10.6 KB
/
macros.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
module ThoughtBot # :nodoc:
module Shoulda # :nodoc:
module Controller # :nodoc:
# = Macro test helpers for your controllers
#
# By using the macro helpers you can quickly and easily create concise and easy to read test suites.
#
# This code segment:
# context "on GET to :show for first record" do
# setup do
# get :show, :id => 1
# end
#
# should_assign_to :user
# should_respond_with :success
# should_render_template :show
# should_not_set_the_flash
#
# should "do something else really cool" do
# assert_equal 1, assigns(:user).id
# end
# end
#
# Would produce 5 tests for the +show+ action
#
# Furthermore, the should_be_restful helper will create an entire set of tests which will verify that your
# controller responds restfully to a variety of requested formats.
module Macros
# :section: should_be_restful
# Generates a full suite of tests for a restful controller.
#
# The following definition will generate tests for the +index+, +show+, +new+,
# +edit+, +create+, +update+ and +destroy+ actions, in both +html+ and +xml+ formats:
#
# should_be_restful do |resource|
# resource.parent = :user
#
# resource.create.params = { :title => "first post", :body => 'blah blah blah'}
# resource.update.params = { :title => "changed" }
# end
#
# This generates about 40 tests, all of the format:
# "on GET to :show should assign @user."
# "on GET to :show should not set the flash."
# "on GET to :show should render 'show' template."
# "on GET to :show should respond with success."
# "on GET to :show as xml should assign @user."
# "on GET to :show as xml should have ContentType set to 'application/xml'."
# "on GET to :show as xml should respond with success."
# "on GET to :show as xml should return <user/> as the root element."
# The +resource+ parameter passed into the block is a ResourceOptions object, and
# is used to configure the tests for the details of your resources.
#
def should_be_restful(&blk) # :yields: resource
resource = ResourceOptions.new
blk.call(resource)
resource.normalize!(self)
resource.formats.each do |format|
resource.actions.each do |action|
if self.respond_to? :"make_#{action}_#{format}_tests"
self.send(:"make_#{action}_#{format}_tests", resource)
else
should "test #{action} #{format}" do
flunk "Test for #{action} as #{format} not implemented"
end
end
end
end
end
# :section: Test macros
# Macro that creates a test asserting that the flash contains the given value.
# val can be a String, a Regex, or nil (indicating that the flash should not be set)
#
# Example:
#
# should_set_the_flash_to "Thank you for placing this order."
# should_set_the_flash_to /created/i
# should_set_the_flash_to nil
def should_set_the_flash_to(val)
if val
should "have #{val.inspect} in the flash" do
assert_contains flash.values, val, ", Flash: #{flash.inspect}"
end
else
should "not set the flash" do
assert_equal({}, flash, "Flash was set to:\n#{flash.inspect}")
end
end
end
# Macro that creates a test asserting that the flash is empty. Same as
# @should_set_the_flash_to nil@
def should_not_set_the_flash
should_set_the_flash_to nil
end
# Macro that creates a test asserting that the controller assigned to
# each of the named instance variable(s).
#
# Example:
#
# should_assign_to :user, :posts
def should_assign_to(*names)
names.each do |name|
should "assign @#{name}" do
assert assigns(name.to_sym), "The action isn't assigning to @#{name}"
end
end
end
# Macro that creates a test asserting that the controller did not assign to
# any of the named instance variable(s).
#
# Example:
#
# should_not_assign_to :user, :posts
def should_not_assign_to(*names)
names.each do |name|
should "not assign to @#{name}" do
assert !assigns(name.to_sym), "@#{name} was visible"
end
end
end
# Macro that creates a test asserting that the controller responded with a 'response' status code.
# Example:
#
# should_respond_with :success
def should_respond_with(response)
should "respond with #{response}" do
assert_response response
end
end
# Macro that creates a test asserting that the response content type was 'content_type'.
# Example:
#
# should_respond_with_content_type 'application/rss+xml'
def should_respond_with_content_type(content_type)
should "respond with content type of #{content_type}" do
content_type = Mime::EXTENSION_LOOKUP[content_type.to_s].to_s if content_type.is_a? Symbol
if content_type.is_a? Regexp
assert_match content_type, @response.content_type, "Expected to match #{content_type} but was actually #{@response.content_type}"
else
assert_equal content_type, @response.content_type, "Expected #{content_type} but was actually #{@response.content_type}"
end
end
end
# Macro that creates a test asserting that a value returned from the session is correct.
# The given string is evaled to produce the resulting redirect path. All of the instance variables
# set by the controller are available to the evaled string.
# Example:
#
# should_return_from_session :user_id, '@user.id'
# should_return_from_session :message, '"Free stuff"'
def should_return_from_session(key, expected)
should "return the correct value from the session for key #{key}" do
instantiate_variables_from_assigns do
expected_value = eval(expected, self.send(:binding), __FILE__, __LINE__)
assert_equal expected_value, session[key], "Expected #{expected_value.inspect} but was #{session[key]}"
end
end
end
# Macro that creates a test asserting that the controller rendered the given template.
# Example:
#
# should_render_template :new
def should_render_template(template)
should "render template #{template.inspect}" do
assert_template template.to_s
end
end
# Macro that creates a test asserting that the controller rendered with the given layout.
# Example:
#
# should_render_with_layout 'special'
def should_render_with_layout(expected_layout = 'application')
if expected_layout
should "render with #{expected_layout} layout" do
response_layout = @response.layout.blank? ? "" : @response.layout.split('/').last
assert_equal expected_layout,
response_layout,
"Expected to render with layout #{expected_layout} but was rendered with #{response_layout}"
end
else
should "render without layout" do
assert_nil @response.layout,
"Expected no layout, but was rendered using #{@response.layout}"
end
end
end
# Macro that creates a test asserting that the controller rendered without a layout.
# Same as @should_render_with_layout false@
def should_render_without_layout
should_render_with_layout nil
end
# Macro that creates a test asserting that the controller returned a redirect to the given path.
# The given string is evaled to produce the resulting redirect path. All of the instance variables
# set by the controller are available to the evaled string.
# Example:
#
# should_redirect_to '"/"'
# should_redirect_to "users_url(@user)"
def should_redirect_to(url)
should "redirect to #{url.inspect}" do
instantiate_variables_from_assigns do
assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__)
end
end
end
# Macro that creates a test asserting that the rendered view contains a <form> element.
def should_render_a_form
should "display a form" do
assert_select "form", true, "The template doesn't contain a <form> element"
end
end
# Macro that creates a routing test. It tries to use the given HTTP
# +method+ on the given +path+, and asserts that it routes to the
# given +options+.
#
# If you don't specify a :controller, it will try to guess the controller
# based on the current test.
#
# +to_param+ is called on the +options+ given.
#
# Examples:
#
# should_route :get, '/posts', :action => :index
# should_route :post, '/posts', :controller => :posts, :action => :create
# should_route :get, '/posts/1', :action => :show, :id => 1
# should_route :put, '/posts/1', :action => :update, :id => "1"
# should_route :delete, '/posts/1', :action => :destroy, :id => 1
# should_route :get, '/posts/new', :action => :new
#
def should_route(method, path, options)
unless options[:controller]
options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
end
options[:controller] = options[:controller].to_s
options[:action] = options[:action].to_s
populated_path = path.dup
options.each do |key, value|
options[key] = value.to_param if value.respond_to? :to_param
populated_path.gsub!(key.inspect, value.to_s)
end
should_name = "route #{method.to_s.upcase} #{populated_path} to/from #{options.inspect}"
should should_name do
assert_routing({:method => method, :path => populated_path}, options)
end
end
end
end
end
end