thoughtbot-shoulda 2.9.1 → 2.9.2

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 (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