rspec-rails 2.8.0.rc1 → 2.8.0.rc2
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/License.txt +22 -0
- data/README.md +253 -119
- data/features/README.md +0 -2
- data/features/Upgrade.md +1 -1
- data/lib/generators/rspec/install/templates/spec/spec_helper.rb +1 -1
- data/lib/generators/rspec/integration/integration_generator.rb +1 -0
- data/lib/generators/rspec/scaffold/scaffold_generator.rb +1 -0
- data/lib/generators/rspec/scaffold/templates/controller_spec.rb +23 -16
- data/lib/rspec/rails/adapters.rb +25 -13
- data/lib/rspec/rails/example/controller_example_group.rb +65 -122
- data/lib/rspec/rails/example/helper_example_group.rb +11 -36
- data/lib/rspec/rails/example/mailer_example_group.rb +1 -1
- data/lib/rspec/rails/example/rails_example_group.rb +5 -0
- data/lib/rspec/rails/example/request_example_group.rb +4 -19
- data/lib/rspec/rails/example/routing_example_group.rb +8 -10
- data/lib/rspec/rails/example/view_example_group.rb +21 -35
- data/lib/rspec/rails/extensions/active_record/base.rb +15 -12
- data/lib/rspec/rails/fixture_support.rb +1 -1
- data/lib/rspec/rails/matchers/be_a_new.rb +63 -30
- data/lib/rspec/rails/matchers/be_new_record.rb +18 -3
- data/lib/rspec/rails/matchers/have_extension.rb +26 -14
- data/lib/rspec/rails/matchers/redirect_to.rb +26 -7
- data/lib/rspec/rails/matchers/relation_match_array.rb +1 -1
- data/lib/rspec/rails/matchers/render_template.rb +27 -8
- data/lib/rspec/rails/matchers/routing_matchers.rb +72 -24
- data/lib/rspec/rails/mocks.rb +42 -34
- data/lib/rspec/rails/module_inclusion.rb +2 -1
- data/lib/rspec/rails/version.rb +1 -1
- data/lib/rspec/rails/view_assigns.rb +31 -34
- data/lib/rspec/rails/view_rendering.rb +10 -6
- data/spec/rspec/rails/example/controller_example_group_spec.rb +2 -2
- data/spec/rspec/rails/example/helper_example_group_spec.rb +5 -5
- data/spec/rspec/rails/example/view_example_group_spec.rb +5 -5
- data/spec/rspec/rails/matchers/be_a_new_spec.rb +2 -0
- data/spec/rspec/rails/matchers/be_new_record_spec.rb +2 -0
- data/spec/rspec/rails/matchers/render_template_spec.rb +3 -5
- data/spec/rspec/rails/mocks/mock_model_spec.rb +28 -0
- metadata +22 -19
data/features/README.md
CHANGED
data/features/Upgrade.md
CHANGED
@@ -36,7 +36,7 @@ is what you need to change:
|
|
36
36
|
|
37
37
|
## Controller specs
|
38
38
|
|
39
|
-
###
|
39
|
+
### isolation from view templates
|
40
40
|
|
41
41
|
By default, controller specs do _not_ render view templates. This keeps
|
42
42
|
controller specs isolated from the content of views and their requirements.
|
@@ -26,12 +26,19 @@ describe <%= controller_class_name %>Controller do
|
|
26
26
|
def valid_attributes
|
27
27
|
{}
|
28
28
|
end
|
29
|
+
|
30
|
+
# This should return the minimal set of values that should be in the session
|
31
|
+
# in order to pass any filters (e.g. authentication) defined in
|
32
|
+
# <%= controller_class_name %>Controller. Be sure to keep this updated too.
|
33
|
+
def valid_session
|
34
|
+
{}
|
35
|
+
end
|
29
36
|
|
30
37
|
<% unless options[:singleton] -%>
|
31
38
|
describe "GET index" do
|
32
39
|
it "assigns all <%= table_name.pluralize %> as @<%= table_name.pluralize %>" do
|
33
40
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
34
|
-
get :index
|
41
|
+
get :index, {}, valid_session
|
35
42
|
assigns(:<%= table_name %>).should eq([<%= file_name %>])
|
36
43
|
end
|
37
44
|
end
|
@@ -40,14 +47,14 @@ describe <%= controller_class_name %>Controller do
|
|
40
47
|
describe "GET show" do
|
41
48
|
it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
|
42
49
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
43
|
-
get :show, :id => <%= file_name %>.
|
50
|
+
get :show, {:id => <%= file_name %>.to_param}, valid_session
|
44
51
|
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>)
|
45
52
|
end
|
46
53
|
end
|
47
54
|
|
48
55
|
describe "GET new" do
|
49
56
|
it "assigns a new <%= ns_file_name %> as @<%= ns_file_name %>" do
|
50
|
-
get :new
|
57
|
+
get :new, {}, valid_session
|
51
58
|
assigns(:<%= ns_file_name %>).should be_a_new(<%= class_name %>)
|
52
59
|
end
|
53
60
|
end
|
@@ -55,7 +62,7 @@ describe <%= controller_class_name %>Controller do
|
|
55
62
|
describe "GET edit" do
|
56
63
|
it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
|
57
64
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
58
|
-
get :edit, :id => <%= file_name %>.
|
65
|
+
get :edit, {:id => <%= file_name %>.to_param}, valid_session
|
59
66
|
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>)
|
60
67
|
end
|
61
68
|
end
|
@@ -64,18 +71,18 @@ describe <%= controller_class_name %>Controller do
|
|
64
71
|
describe "with valid params" do
|
65
72
|
it "creates a new <%= class_name %>" do
|
66
73
|
expect {
|
67
|
-
post :create, :<%= ns_file_name %> => valid_attributes
|
74
|
+
post :create, {:<%= ns_file_name %> => valid_attributes}, valid_session
|
68
75
|
}.to change(<%= class_name %>, :count).by(1)
|
69
76
|
end
|
70
77
|
|
71
78
|
it "assigns a newly created <%= ns_file_name %> as @<%= ns_file_name %>" do
|
72
|
-
post :create, :<%= ns_file_name %> => valid_attributes
|
79
|
+
post :create, {:<%= ns_file_name %> => valid_attributes}, valid_session
|
73
80
|
assigns(:<%= ns_file_name %>).should be_a(<%= class_name %>)
|
74
81
|
assigns(:<%= ns_file_name %>).should be_persisted
|
75
82
|
end
|
76
83
|
|
77
84
|
it "redirects to the created <%= ns_file_name %>" do
|
78
|
-
post :create, :<%= ns_file_name %> => valid_attributes
|
85
|
+
post :create, {:<%= ns_file_name %> => valid_attributes}, valid_session
|
79
86
|
response.should redirect_to(<%= class_name %>.last)
|
80
87
|
end
|
81
88
|
end
|
@@ -84,14 +91,14 @@ describe <%= controller_class_name %>Controller do
|
|
84
91
|
it "assigns a newly created but unsaved <%= ns_file_name %> as @<%= ns_file_name %>" do
|
85
92
|
# Trigger the behavior that occurs when invalid params are submitted
|
86
93
|
<%= class_name %>.any_instance.stub(:save).and_return(false)
|
87
|
-
post :create, :<%= ns_file_name %> => {}
|
94
|
+
post :create, {:<%= ns_file_name %> => {}}, valid_session
|
88
95
|
assigns(:<%= ns_file_name %>).should be_a_new(<%= class_name %>)
|
89
96
|
end
|
90
97
|
|
91
98
|
it "re-renders the 'new' template" do
|
92
99
|
# Trigger the behavior that occurs when invalid params are submitted
|
93
100
|
<%= class_name %>.any_instance.stub(:save).and_return(false)
|
94
|
-
post :create, :<%= ns_file_name %> => {}
|
101
|
+
post :create, {:<%= ns_file_name %> => {}}, valid_session
|
95
102
|
response.should render_template("new")
|
96
103
|
end
|
97
104
|
end
|
@@ -106,18 +113,18 @@ describe <%= controller_class_name %>Controller do
|
|
106
113
|
# receives the :update_attributes message with whatever params are
|
107
114
|
# submitted in the request.
|
108
115
|
<%= class_name %>.any_instance.should_receive(:update_attributes).with(<%= params %>)
|
109
|
-
put :update, :id => <%= file_name %>.
|
116
|
+
put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= params %>}, valid_session
|
110
117
|
end
|
111
118
|
|
112
119
|
it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
|
113
120
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
114
|
-
put :update, :id => <%= file_name %>.
|
121
|
+
put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => valid_attributes}, valid_session
|
115
122
|
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>)
|
116
123
|
end
|
117
124
|
|
118
125
|
it "redirects to the <%= ns_file_name %>" do
|
119
126
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
120
|
-
put :update, :id => <%= file_name %>.
|
127
|
+
put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => valid_attributes}, valid_session
|
121
128
|
response.should redirect_to(<%= file_name %>)
|
122
129
|
end
|
123
130
|
end
|
@@ -127,7 +134,7 @@ describe <%= controller_class_name %>Controller do
|
|
127
134
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
128
135
|
# Trigger the behavior that occurs when invalid params are submitted
|
129
136
|
<%= class_name %>.any_instance.stub(:save).and_return(false)
|
130
|
-
put :update, :id => <%= file_name %>.
|
137
|
+
put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => {}}, valid_session
|
131
138
|
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>)
|
132
139
|
end
|
133
140
|
|
@@ -135,7 +142,7 @@ describe <%= controller_class_name %>Controller do
|
|
135
142
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
136
143
|
# Trigger the behavior that occurs when invalid params are submitted
|
137
144
|
<%= class_name %>.any_instance.stub(:save).and_return(false)
|
138
|
-
put :update, :id => <%= file_name %>.
|
145
|
+
put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => {}}, valid_session
|
139
146
|
response.should render_template("edit")
|
140
147
|
end
|
141
148
|
end
|
@@ -145,13 +152,13 @@ describe <%= controller_class_name %>Controller do
|
|
145
152
|
it "destroys the requested <%= ns_file_name %>" do
|
146
153
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
147
154
|
expect {
|
148
|
-
delete :destroy, :id => <%= file_name %>.
|
155
|
+
delete :destroy, {:id => <%= file_name %>.to_param}, valid_session
|
149
156
|
}.to change(<%= class_name %>, :count).by(-1)
|
150
157
|
end
|
151
158
|
|
152
159
|
it "redirects to the <%= table_name %> list" do
|
153
160
|
<%= file_name %> = <%= class_name %>.create! valid_attributes
|
154
|
-
delete :destroy, :id => <%= file_name %>.
|
161
|
+
delete :destroy, {:id => <%= file_name %>.to_param}, valid_session
|
155
162
|
response.should redirect_to(<%= index_helper %>_url)
|
156
163
|
end
|
157
164
|
end
|
data/lib/rspec/rails/adapters.rb
CHANGED
@@ -7,50 +7,62 @@ module RSpec
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
module ClassMethods
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
# Wraps `setup` calls from within Rails' testing framework in `before`
|
13
|
+
# hooks.
|
10
14
|
def setup(*methods)
|
11
15
|
methods.each {|method| before { send method } }
|
12
16
|
end
|
13
17
|
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
# Wraps `teardown` calls from within Rails' testing framework in
|
21
|
+
# `after` hooks.
|
14
22
|
def teardown(*methods)
|
15
23
|
methods.each {|method| after { send method } }
|
16
24
|
end
|
17
25
|
end
|
18
26
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
27
|
+
# @api private
|
28
|
+
def method_name
|
29
|
+
@example
|
23
30
|
end
|
24
31
|
end
|
25
32
|
|
26
33
|
module TestUnitAssertionAdapter
|
27
34
|
extend ActiveSupport::Concern
|
28
35
|
|
29
|
-
class AssertionDelegate
|
30
|
-
include Test::Unit::Assertions
|
31
|
-
end
|
32
|
-
|
33
36
|
module ClassMethods
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
# Returns the names of assertion methods that we want to expose to
|
40
|
+
# examples without exposing non-assertion methods in Test::Unit or
|
41
|
+
# Minitest.
|
34
42
|
def assertion_method_names
|
35
43
|
Test::Unit::Assertions.public_instance_methods.select{|m| m.to_s =~ /^(assert|flunk)/} +
|
36
44
|
[:build_message]
|
37
45
|
end
|
38
46
|
|
47
|
+
# @api private
|
39
48
|
def define_assertion_delegators
|
40
49
|
assertion_method_names.each do |m|
|
41
50
|
class_eval <<-CODE
|
42
51
|
def #{m}(*args, &block)
|
43
|
-
|
52
|
+
assertion_delegator.send :#{m}, *args, &block
|
44
53
|
end
|
45
54
|
CODE
|
46
55
|
end
|
47
56
|
end
|
48
57
|
end
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
59
|
+
class AssertionDelegator
|
60
|
+
include Test::Unit::Assertions
|
61
|
+
end
|
62
|
+
|
63
|
+
# @api private
|
64
|
+
def assertion_delegator
|
65
|
+
@assertion_delegator ||= AssertionDelegator.new
|
54
66
|
end
|
55
67
|
|
56
68
|
included do
|
@@ -3,81 +3,6 @@ RSpec.configure do |config|
|
|
3
3
|
end
|
4
4
|
|
5
5
|
module RSpec::Rails
|
6
|
-
# Extends ActionController::TestCase::Behavior to work with RSpec.
|
7
|
-
#
|
8
|
-
# == Examples
|
9
|
-
#
|
10
|
-
# == with stubs
|
11
|
-
#
|
12
|
-
# describe WidgetsController do
|
13
|
-
# describe "GET index" do
|
14
|
-
# it "assigns all widgets to @widgets" do
|
15
|
-
# widget = stub_model(Widget)
|
16
|
-
# Widget.stub(:all) { widget }
|
17
|
-
# get :index
|
18
|
-
# assigns(:widgets).should eq([widget])
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# === with a factory
|
24
|
-
#
|
25
|
-
# describe WidgetsController do
|
26
|
-
# describe "GET index" do
|
27
|
-
# it "assigns all widgets to @widgets" do
|
28
|
-
# widget = Factory(:widget)
|
29
|
-
# get :index
|
30
|
-
# assigns(:widgets).should eq([widget])
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
# end
|
34
|
-
#
|
35
|
-
# === with fixtures
|
36
|
-
#
|
37
|
-
# describe WidgetsController do
|
38
|
-
# describe "GET index" do
|
39
|
-
# fixtures :widgets
|
40
|
-
#
|
41
|
-
# it "assigns all widgets to @widgets" do
|
42
|
-
# get :index
|
43
|
-
# assigns(:widgets).should eq(Widget.all)
|
44
|
-
# end
|
45
|
-
# end
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# == Matchers
|
49
|
-
#
|
50
|
-
# In addition to the stock matchers from rspec-expectations, controller
|
51
|
-
# specs add these matchers, which delegate to rails' assertions:
|
52
|
-
#
|
53
|
-
# response.should render_template(*args)
|
54
|
-
# => delegates to assert_template(*args)
|
55
|
-
#
|
56
|
-
# response.should redirect_to(destination)
|
57
|
-
# => delegates to assert_redirected_to(destination)
|
58
|
-
#
|
59
|
-
# == Isolation from views
|
60
|
-
#
|
61
|
-
# RSpec's preferred approach to spec'ing controller behaviour is to isolate
|
62
|
-
# the controller from its collaborators. By default, therefore, controller
|
63
|
-
# example groups do not render the views in your app. Due to the way Rails
|
64
|
-
# searches for view templates, the template still needs to exist, but it
|
65
|
-
# won't actually be loaded.
|
66
|
-
#
|
67
|
-
# NOTE that this is different from rspec-rails-1 with rails-2, which did not
|
68
|
-
# require the presence of the file at all. Due to changes in rails-3, this
|
69
|
-
# was no longer feasible in rspec-rails-2.
|
70
|
-
#
|
71
|
-
# == View rendering
|
72
|
-
#
|
73
|
-
# If you prefer a more integrated approach, similar to that of Rails'
|
74
|
-
# functional tests, you can tell controller groups to render the views in the
|
75
|
-
# app with the +render_views+ declaration:
|
76
|
-
#
|
77
|
-
# describe WidgetsController do
|
78
|
-
# render_views
|
79
|
-
# ...
|
80
|
-
#
|
81
6
|
module ControllerExampleGroup
|
82
7
|
extend ActiveSupport::Concern
|
83
8
|
include RSpec::Rails::RailsExampleGroup
|
@@ -88,53 +13,53 @@ module RSpec::Rails
|
|
88
13
|
include RSpec::Rails::Matchers::RoutingMatchers
|
89
14
|
|
90
15
|
module ClassMethods
|
16
|
+
# @private
|
91
17
|
def controller_class
|
92
|
-
|
18
|
+
described_class
|
93
19
|
end
|
94
20
|
|
95
|
-
# Supports a simple DSL for specifying
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# defined in <tt>config/routes.rb</tt>.
|
21
|
+
# Supports a simple DSL for specifying behavior of ApplicationController.
|
22
|
+
# Creates an anonymous subclass of ApplicationController and evals the
|
23
|
+
# `body` in that context. Also sets up implicit routes for this
|
24
|
+
# controller, that are separate from those defined in "config/routes.rb".
|
100
25
|
#
|
101
|
-
#
|
26
|
+
# @note Due to Ruby 1.8 scoping rules in anoymous subclasses, constants
|
27
|
+
# defined in `ApplicationController` must be fully qualified (e.g.
|
28
|
+
# `ApplicationController::AccessDenied`) in the block passed to the
|
29
|
+
# `controller` method. Any instance methods, filters, etc, that are
|
30
|
+
# defined in `ApplicationController`, however, are accessible from
|
31
|
+
# within the block.
|
102
32
|
#
|
103
|
-
#
|
104
|
-
# controller do
|
105
|
-
# def index
|
106
|
-
# raise ApplicationController::AccessDenied
|
107
|
-
# end
|
108
|
-
# end
|
33
|
+
# @example
|
109
34
|
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
35
|
+
# describe ApplicationController do
|
36
|
+
# controller do
|
37
|
+
# def index
|
38
|
+
# raise ApplicationController::AccessDenied
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# describe "handling AccessDenied exceptions" do
|
43
|
+
# it "redirects to the /401.html page" do
|
44
|
+
# get :index
|
45
|
+
# response.should redirect_to("/401.html")
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# end
|
117
49
|
#
|
118
50
|
# If you would like to spec a subclass of ApplicationController, call
|
119
51
|
# controller like so:
|
120
52
|
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
# NOTICE: Due to Ruby 1.8 scoping rules in anoymous subclasses, constants
|
126
|
-
# defined in +ApplicationController+ must be fully qualified (e.g.
|
127
|
-
# ApplicationController::AccessDenied) in the block passed to the
|
128
|
-
# +controller+ method. Any instance methods, filters, etc, that are
|
129
|
-
# defined in +ApplicationController+, however, are accessible from within
|
130
|
-
# the block.
|
53
|
+
# controller(ApplicationControllerSubclass) do
|
54
|
+
# # ....
|
55
|
+
# end
|
131
56
|
def controller(base_class = nil, &body)
|
132
57
|
base_class ||= RSpec.configuration.infer_base_class_for_anonymous_controllers? ?
|
133
58
|
controller_class :
|
134
59
|
ApplicationController
|
135
60
|
|
136
|
-
metadata[:example_group][:
|
137
|
-
metadata[:example_group][:
|
61
|
+
metadata[:example_group][:described_class] = Class.new(base_class, &body)
|
62
|
+
metadata[:example_group][:described_class].singleton_class.class_eval do
|
138
63
|
def name; "AnonymousController" end
|
139
64
|
end
|
140
65
|
|
@@ -149,25 +74,43 @@ module RSpec::Rails
|
|
149
74
|
end
|
150
75
|
end
|
151
76
|
|
152
|
-
|
153
|
-
attr_reader :controller, :routes
|
77
|
+
attr_reader :controller, :routes
|
154
78
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
end
|
79
|
+
module BypassRescue
|
80
|
+
def rescue_with_handler(exception)
|
81
|
+
raise exception
|
159
82
|
end
|
83
|
+
end
|
160
84
|
|
161
|
-
|
162
|
-
|
163
|
-
|
85
|
+
# Extends the controller with a module that overrides
|
86
|
+
# `rescue_with_handler` to raise the exception passed to it. Use this to
|
87
|
+
# specify that an action _should_ raise an exception given appropriate
|
88
|
+
# conditions.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
#
|
92
|
+
# describe ProfilesController do
|
93
|
+
# it "raises a 403 when a non-admin user tries to view another user's profile" do
|
94
|
+
# profile = create_profile
|
95
|
+
# login_as profile.user
|
96
|
+
#
|
97
|
+
# expect do
|
98
|
+
# bypass_rescue
|
99
|
+
# get :show, :id => profile.id + 1
|
100
|
+
# end.to raise_error(/403 Forbidden/)
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
def bypass_rescue
|
104
|
+
controller.extend(BypassRescue)
|
105
|
+
end
|
164
106
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
107
|
+
# If method is a named_route, delegates to the RouteSet associated with
|
108
|
+
# this controller.
|
109
|
+
def method_missing(method, *args, &block)
|
110
|
+
if @orig_routes && @orig_routes.named_routes.helpers.include?(method)
|
111
|
+
controller.send(method, *args, &block)
|
112
|
+
else
|
113
|
+
super
|
171
114
|
end
|
172
115
|
end
|
173
116
|
|