thoughtbot-shoulda 2.9.1 → 2.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README.rdoc +27 -5
  2. data/Rakefile +2 -2
  3. data/lib/shoulda.rb +1 -1
  4. data/lib/shoulda/{controller.rb → action_controller.rb} +6 -8
  5. data/lib/shoulda/{controller → action_controller}/helpers.rb +1 -16
  6. data/lib/shoulda/action_controller/macros.rb +277 -0
  7. data/lib/shoulda/action_controller/matchers.rb +37 -0
  8. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  9. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  10. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  11. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +70 -0
  12. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
  13. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  14. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +83 -0
  15. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  16. data/lib/shoulda/action_view.rb +10 -0
  17. data/lib/shoulda/action_view/macros.rb +56 -0
  18. data/lib/shoulda/active_record/macros.rb +8 -13
  19. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +1 -1
  20. data/lib/shoulda/rails.rb +4 -3
  21. data/lib/shoulda/rspec.rb +7 -5
  22. data/test/functional/posts_controller_test.rb +28 -22
  23. data/test/functional/users_controller_test.rb +0 -19
  24. data/test/matchers/{allow_mass_assignment_of_matcher_test.rb → active_record/allow_mass_assignment_of_matcher_test.rb} +1 -1
  25. data/test/matchers/{allow_value_matcher_test.rb → active_record/allow_value_matcher_test.rb} +1 -1
  26. data/test/matchers/{association_matcher_test.rb → active_record/association_matcher_test.rb} +1 -1
  27. data/test/matchers/{ensure_inclusion_of_matcher_test.rb → active_record/ensure_inclusion_of_matcher_test.rb} +1 -1
  28. data/test/matchers/{ensure_length_of_matcher_test.rb → active_record/ensure_length_of_matcher_test.rb} +1 -1
  29. data/test/matchers/{have_db_column_matcher_test.rb → active_record/have_db_column_matcher_test.rb} +1 -1
  30. data/test/matchers/{have_index_matcher_test.rb → active_record/have_index_matcher_test.rb} +1 -1
  31. data/test/matchers/{have_named_scope_matcher_test.rb → active_record/have_named_scope_matcher_test.rb} +1 -1
  32. data/test/matchers/{have_readonly_attributes_matcher_test.rb → active_record/have_readonly_attributes_matcher_test.rb} +1 -1
  33. data/test/matchers/{validate_acceptance_of_matcher_test.rb → active_record/validate_acceptance_of_matcher_test.rb} +1 -1
  34. data/test/matchers/{validate_numericality_of_matcher_test.rb → active_record/validate_numericality_of_matcher_test.rb} +1 -1
  35. data/test/matchers/{validate_presence_of_matcher_test.rb → active_record/validate_presence_of_matcher_test.rb} +1 -1
  36. data/test/matchers/{validate_uniqueness_of_matcher_test.rb → active_record/validate_uniqueness_of_matcher_test.rb} +8 -2
  37. data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
  38. data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
  39. data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
  40. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +27 -0
  41. data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
  42. data/test/matchers/controller/route_matcher_test.rb +58 -0
  43. data/test/matchers/controller/set_session_matcher_test.rb +27 -0
  44. data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
  45. data/test/model_builder.rb +47 -2
  46. data/test/rails_root/app/models/user.rb +2 -1
  47. data/test/rails_root/config/environment.rb +1 -1
  48. data/test/rspec_test.rb +207 -0
  49. data/test/unit/user_test.rb +10 -1
  50. metadata +43 -24
  51. data/lib/shoulda/controller/formats/html.rb +0 -199
  52. data/lib/shoulda/controller/formats/xml.rb +0 -168
  53. data/lib/shoulda/controller/macros.rb +0 -336
  54. data/lib/shoulda/controller/resource_options.rb +0 -233
@@ -1,168 +0,0 @@
1
- module Shoulda # :nodoc:
2
- module Controller # :nodoc:
3
- module XML
4
- def self.included(other) #:nodoc:
5
- other.class_eval do
6
- extend Shoulda::Controller::XML::ClassMethods
7
- end
8
- end
9
-
10
- module ClassMethods
11
- # Macro that creates a test asserting that the controller responded with an XML content-type
12
- # and that the XML contains +<name/>+ as the root element.
13
- def should_respond_with_xml_for(name = nil)
14
- should "have ContentType set to 'application/xml'" do
15
- assert_xml_response
16
- end
17
-
18
- if name
19
- should "return <#{name}/> as the root element" do
20
- body = @response.body.first(100).map {|l| " #{l}"}
21
- assert_select name.to_s.dasherize, 1, "Body:\n#{body}...\nDoes not have <#{name}/> as the root element."
22
- end
23
- end
24
- end
25
- alias should_respond_with_xml should_respond_with_xml_for
26
-
27
- protected
28
-
29
- def make_show_xml_tests(res) # :nodoc:
30
- context "on GET to #{controller_name_from_class}#show as xml" do
31
- setup do
32
- request_xml
33
- record = get_existing_record(res)
34
- parent_params = make_parent_params(res, record)
35
- get :show, parent_params.merge({ res.identifier => record.to_param })
36
- end
37
-
38
- if res.denied.actions.include?(:show)
39
- should_not_assign_to res.object
40
- should_respond_with 401
41
- else
42
- should_assign_to res.object
43
- should_respond_with :success
44
- should_respond_with_xml_for res.object
45
- end
46
- end
47
- end
48
-
49
- def make_edit_xml_tests(res) # :nodoc:
50
- # XML doesn't need an :edit action
51
- end
52
-
53
- def make_new_xml_tests(res) # :nodoc:
54
- # XML doesn't need a :new action
55
- end
56
-
57
- def make_index_xml_tests(res) # :nodoc:
58
- context "on GET to #{controller_name_from_class}#index as xml" do
59
- setup do
60
- request_xml
61
- parent_params = make_parent_params(res)
62
- get(:index, parent_params)
63
- end
64
-
65
- if res.denied.actions.include?(:index)
66
- should_not_assign_to res.object.to_s.pluralize
67
- should_respond_with 401
68
- else
69
- should_respond_with :success
70
- should_respond_with_xml_for res.object.to_s.pluralize
71
- should_assign_to res.object.to_s.pluralize
72
- end
73
- end
74
- end
75
-
76
- def make_destroy_xml_tests(res) # :nodoc:
77
- context "on DELETE to #{controller_name_from_class}#destroy as xml" do
78
- setup do
79
- request_xml
80
- @record = get_existing_record(res)
81
- parent_params = make_parent_params(res, @record)
82
- delete :destroy, parent_params.merge({ res.identifier => @record.to_param })
83
- end
84
-
85
- if res.denied.actions.include?(:destroy)
86
- should_respond_with 401
87
-
88
- should "not destroy record" do
89
- assert @record.reload
90
- end
91
- else
92
- should "destroy record" do
93
- assert_raises(::ActiveRecord::RecordNotFound, "@#{res.object} was not destroyed.") do
94
- @record.reload
95
- end
96
- end
97
- end
98
- end
99
- end
100
-
101
- def make_create_xml_tests(res) # :nodoc:
102
- context "on POST to #{controller_name_from_class}#create as xml" do
103
- setup do
104
- request_xml
105
- parent_params = make_parent_params(res)
106
- @count = res.klass.count
107
- post :create, parent_params.merge(res.object => res.create.params)
108
- end
109
-
110
- if res.denied.actions.include?(:create)
111
- should_respond_with 401
112
- should_not_assign_to res.object
113
-
114
- should "not create new record" do
115
- assert_equal @count, res.klass.count
116
- end
117
- else
118
- should_assign_to res.object
119
-
120
- should "not have errors on @#{res.object}" do
121
- assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:"
122
- end
123
- end
124
- end
125
- end
126
-
127
- def make_update_xml_tests(res) # :nodoc:
128
- context "on PUT to #{controller_name_from_class}#update as xml" do
129
- setup do
130
- request_xml
131
- @record = get_existing_record(res)
132
- parent_params = make_parent_params(res, @record)
133
- put :update, parent_params.merge(res.identifier => @record.to_param, res.object => res.update.params)
134
- end
135
-
136
- if res.denied.actions.include?(:update)
137
- should_not_assign_to res.object
138
- should_respond_with 401
139
- else
140
- should_assign_to res.object
141
-
142
- should "not have errors on @#{res.object}" do
143
- assert_equal [], assigns(res.object).errors.full_messages, "@#{res.object} has errors:"
144
- end
145
- end
146
- end
147
- end
148
- end
149
-
150
- # Sets the next request's format to 'application/xml'
151
- def request_xml
152
- @request.accept = "application/xml"
153
- end
154
-
155
- # Asserts that the controller's response was 'application/xml'
156
- def assert_xml_response
157
- content_type = (@response.headers["Content-Type"] || @response.headers["type"]).to_s
158
- regex = %r{\bapplication/xml\b}
159
-
160
- msg = "Content Type '#{content_type.inspect}' doesn't match '#{regex.inspect}'\n"
161
- msg += "Body: #{@response.body.first(100).chomp} ..."
162
-
163
- assert_match regex, content_type, msg
164
- end
165
-
166
- end
167
- end
168
- end
@@ -1,336 +0,0 @@
1
- module Shoulda # :nodoc:
2
- module Controller # :nodoc:
3
- # = Macro test helpers for your controllers
4
- #
5
- # By using the macro helpers you can quickly and easily create concise and easy to read test suites.
6
- #
7
- # This code segment:
8
- # context "on GET to :show for first record" do
9
- # setup do
10
- # get :show, :id => 1
11
- # end
12
- #
13
- # should_assign_to :user
14
- # should_respond_with :success
15
- # should_render_template :show
16
- # should_not_set_the_flash
17
- #
18
- # should "do something else really cool" do
19
- # assert_equal 1, assigns(:user).id
20
- # end
21
- # end
22
- #
23
- # Would produce 5 tests for the +show+ action
24
- #
25
- # Furthermore, the should_be_restful helper will create an entire set of tests which will verify that your
26
- # controller responds restfully to a variety of requested formats.
27
- module Macros
28
- # <b>DEPRECATED:</b> Please see
29
- # http://thoughtbot.lighthouseapp.com/projects/5807/tickets/78 for more
30
- # information.
31
- #
32
- # Generates a full suite of tests for a restful controller.
33
- #
34
- # The following definition will generate tests for the +index+, +show+, +new+,
35
- # +edit+, +create+, +update+ and +destroy+ actions, in both +html+ and +xml+ formats:
36
- #
37
- # should_be_restful do |resource|
38
- # resource.parent = :user
39
- #
40
- # resource.create.params = { :title => "first post", :body => 'blah blah blah'}
41
- # resource.update.params = { :title => "changed" }
42
- # end
43
- #
44
- # This generates about 40 tests, all of the format:
45
- # "on GET to :show should assign @user."
46
- # "on GET to :show should not set the flash."
47
- # "on GET to :show should render 'show' template."
48
- # "on GET to :show should respond with success."
49
- # "on GET to :show as xml should assign @user."
50
- # "on GET to :show as xml should have ContentType set to 'application/xml'."
51
- # "on GET to :show as xml should respond with success."
52
- # "on GET to :show as xml should return <user/> as the root element."
53
- # The +resource+ parameter passed into the block is a ResourceOptions object, and
54
- # is used to configure the tests for the details of your resources.
55
- #
56
- def should_be_restful(&blk) # :yields: resource
57
- warn "[DEPRECATION] should_be_restful is deprecated. Please see http://thoughtbot.lighthouseapp.com/projects/5807/tickets/78 for more information."
58
-
59
- resource = ResourceOptions.new
60
- blk.call(resource)
61
- resource.normalize!(self)
62
-
63
- resource.formats.each do |format|
64
- resource.actions.each do |action|
65
- if self.respond_to? :"make_#{action}_#{format}_tests"
66
- self.send(:"make_#{action}_#{format}_tests", resource)
67
- else
68
- should "test #{action} #{format}" do
69
- flunk "Test for #{action} as #{format} not implemented"
70
- end
71
- end
72
- end
73
- end
74
- end
75
-
76
- # :section: Test macros
77
- # Macro that creates a test asserting that the flash contains the given value.
78
- # val can be a String, a Regex, or nil (indicating that the flash should not be set)
79
- #
80
- # Example:
81
- #
82
- # should_set_the_flash_to "Thank you for placing this order."
83
- # should_set_the_flash_to /created/i
84
- # should_set_the_flash_to nil
85
- def should_set_the_flash_to(val)
86
- if val
87
- should "have #{val.inspect} in the flash" do
88
- assert_contains flash.values, val, ", Flash: #{flash.inspect}"
89
- end
90
- else
91
- should "not set the flash" do
92
- assert_equal({}, flash, "Flash was set to:\n#{flash.inspect}")
93
- end
94
- end
95
- end
96
-
97
- # Macro that creates a test asserting that the flash is empty. Same as
98
- # @should_set_the_flash_to nil@
99
- def should_not_set_the_flash
100
- should_set_the_flash_to nil
101
- end
102
-
103
- # Macro that creates a test asserting that filter_parameter_logging
104
- # is set for the specified keys
105
- #
106
- # Example:
107
- #
108
- # should_filter_params :password, :ssn
109
- def should_filter_params(*keys)
110
- keys.each do |key|
111
- should "filter #{key}" do
112
- assert @controller.respond_to?(:filter_parameters),
113
- "The key #{key} is not filtered"
114
- filtered = @controller.send(:filter_parameters, {key.to_s => key.to_s})
115
- assert_equal '[FILTERED]', filtered[key.to_s],
116
- "The key #{key} is not filtered"
117
- end
118
- end
119
- end
120
-
121
- # Macro that creates a test asserting that the controller assigned to
122
- # each of the named instance variable(s).
123
- #
124
- # Options:
125
- # * <tt>:class</tt> - The expected class of the instance variable being checked.
126
- # * <tt>:equals</tt> - A string which is evaluated and compared for equality with
127
- # the instance variable being checked.
128
- #
129
- # Example:
130
- #
131
- # should_assign_to :user, :posts
132
- # should_assign_to :user, :class => User
133
- # should_assign_to :user, :equals => '@user'
134
- def should_assign_to(*names)
135
- opts = names.extract_options!
136
- names.each do |name|
137
- test_name = "assign @#{name}"
138
- test_name << " as class #{opts[:class]}" if opts[:class]
139
- test_name << " which is equal to #{opts[:equals]}" if opts[:equals]
140
- should test_name do
141
- assigned_value = assigns(name.to_sym)
142
- assert_not_nil assigned_value, "The action isn't assigning to @#{name}"
143
- assert_kind_of opts[:class], assigned_value if opts[:class]
144
- if opts[:equals]
145
- instantiate_variables_from_assigns do
146
- expected_value = eval(opts[:equals], self.send(:binding), __FILE__, __LINE__)
147
- assert_equal expected_value, assigned_value,
148
- "Instance variable @#{name} expected to be #{expected_value}" +
149
- " but was #{assigned_value}"
150
- end
151
- end
152
- end
153
- end
154
- end
155
-
156
- # Macro that creates a test asserting that the controller did not assign to
157
- # any of the named instance variable(s).
158
- #
159
- # Example:
160
- #
161
- # should_not_assign_to :user, :posts
162
- def should_not_assign_to(*names)
163
- names.each do |name|
164
- should "not assign to @#{name}" do
165
- assert !assigns(name.to_sym), "@#{name} was visible"
166
- end
167
- end
168
- end
169
-
170
- # Macro that creates a test asserting that the controller responded with a 'response' status code.
171
- # Example:
172
- #
173
- # should_respond_with :success
174
- def should_respond_with(response)
175
- should "respond with #{response}" do
176
- assert_response response
177
- end
178
- end
179
-
180
- # Macro that creates a test asserting that the response content type was 'content_type'.
181
- # Example:
182
- #
183
- # should_respond_with_content_type 'application/rss+xml'
184
- # should_respond_with_content_type :rss
185
- # should_respond_with_content_type /rss/
186
- def should_respond_with_content_type(content_type)
187
- should "respond with content type of #{content_type}" do
188
- content_type = Mime::EXTENSION_LOOKUP[content_type.to_s].to_s if content_type.is_a? Symbol
189
- if content_type.is_a? Regexp
190
- assert_match content_type, @response.content_type, "Expected to match #{content_type} but was actually #{@response.content_type}"
191
- else
192
- assert_equal content_type, @response.content_type, "Expected #{content_type} but was actually #{@response.content_type}"
193
- end
194
- end
195
- end
196
-
197
- # Macro that creates a test asserting that a value returned from the session is correct.
198
- # The given string is evaled to produce the resulting redirect path. All of the instance variables
199
- # set by the controller are available to the evaled string.
200
- # Example:
201
- #
202
- # should_return_from_session :user_id, '@user.id'
203
- # should_return_from_session :message, '"Free stuff"'
204
- def should_return_from_session(key, expected)
205
- should "return the correct value from the session for key #{key}" do
206
- instantiate_variables_from_assigns do
207
- expected_value = eval(expected, self.send(:binding), __FILE__, __LINE__)
208
- assert_equal expected_value, session[key], "Expected #{expected_value.inspect} but was #{session[key]}"
209
- end
210
- end
211
- end
212
-
213
- # Macro that creates a test asserting that the controller rendered the given template.
214
- # Example:
215
- #
216
- # should_render_template :new
217
- def should_render_template(template)
218
- should "render template #{template.inspect}" do
219
- assert_template template.to_s
220
- end
221
- end
222
-
223
- # Macro that creates a test asserting that the controller rendered with the given layout.
224
- # Example:
225
- #
226
- # should_render_with_layout 'special'
227
- def should_render_with_layout(expected_layout = 'application')
228
- if expected_layout
229
- should "render with #{expected_layout.inspect} layout" do
230
- response_layout = @response.layout.blank? ? "" : @response.layout.split('/').last
231
- assert_equal expected_layout.to_s,
232
- response_layout,
233
- "Expected to render with layout #{expected_layout} but was rendered with #{response_layout}"
234
- end
235
- else
236
- should "render without layout" do
237
- assert_nil @response.layout,
238
- "Expected no layout, but was rendered using #{@response.layout}"
239
- end
240
- end
241
- end
242
-
243
- # Macro that creates a test asserting that the controller rendered without a layout.
244
- # Same as @should_render_with_layout false@
245
- def should_render_without_layout
246
- should_render_with_layout nil
247
- end
248
-
249
- # Macro that creates a test asserting that the controller returned a redirect to the given path.
250
- # The given string is evaled to produce the resulting redirect path. All of the instance variables
251
- # set by the controller are available to the evaled string.
252
- # Example:
253
- #
254
- # should_redirect_to '"/"'
255
- # should_redirect_to "user_url(@user)"
256
- # should_redirect_to "users_url"
257
- def should_redirect_to(url)
258
- should "redirect to #{url.inspect}" do
259
- instantiate_variables_from_assigns do
260
- assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__)
261
- end
262
- end
263
- end
264
-
265
- # Macro that creates a test asserting that the rendered view contains a <form> element.
266
- def should_render_a_form
267
- should "display a form" do
268
- assert_select "form", true, "The template doesn't contain a <form> element"
269
- end
270
- end
271
-
272
- # Macro that creates a test asserting that the rendered view contains the selected metatags.
273
- # Values can be string or Regexps.
274
- # Example:
275
- #
276
- # should_render_page_with_metadata :description => "Description of this page", :keywords => /post/
277
- #
278
- # You can also use this method to test the rendered views title.
279
- #
280
- # Example:
281
- # should_render_page_with_metadata :title => /index/
282
- def should_render_page_with_metadata(options)
283
- options.each do |key, value|
284
- should "have metatag #{key}" do
285
- if key.to_sym == :title
286
- assert_select "title", value
287
- else
288
- assert_select "meta[name=?][content#{"*" if value.is_a?(Regexp)}=?]", key, value
289
- end
290
- end
291
- end
292
- end
293
-
294
- # Macro that creates a routing test. It tries to use the given HTTP
295
- # +method+ on the given +path+, and asserts that it routes to the
296
- # given +options+.
297
- #
298
- # If you don't specify a :controller, it will try to guess the controller
299
- # based on the current test.
300
- #
301
- # +to_param+ is called on the +options+ given.
302
- #
303
- # Examples:
304
- #
305
- # should_route :get, "/posts", :controller => :posts, :action => :index
306
- # should_route :get, "/posts/new", :action => :new
307
- # should_route :post, "/posts", :action => :create
308
- # should_route :get, "/posts/1", :action => :show, :id => 1
309
- # should_route :edit, "/posts/1", :action => :show, :id => 1
310
- # should_route :put, "/posts/1", :action => :update, :id => 1
311
- # should_route :delete, "/posts/1", :action => :destroy, :id => 1
312
- # should_route :get, "/users/1/posts/1",
313
- # :action => :show, :id => 1, :user_id => 1
314
- #
315
- def should_route(method, path, options)
316
- unless options[:controller]
317
- options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
318
- end
319
- options[:controller] = options[:controller].to_s
320
- options[:action] = options[:action].to_s
321
-
322
- populated_path = path.dup
323
- options.each do |key, value|
324
- options[key] = value.to_param if value.respond_to? :to_param
325
- populated_path.gsub!(key.inspect, value.to_s)
326
- end
327
-
328
- should_name = "route #{method.to_s.upcase} #{populated_path} to/from #{options.inspect}"
329
-
330
- should should_name do
331
- assert_routing({:method => method, :path => populated_path}, options)
332
- end
333
- end
334
- end
335
- end
336
- end