Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 268 lines (231 sloc) 9.152 kB
6d673c2 Made the following renames:
btakita authored
1 module Spec
2 module Rails
3 module Example
4 # Controller Examples live in $RAILS_ROOT/spec/controllers/.
5 #
6853e88 @dchelimsky general cleanup
authored
6 # Controller Examples use Spec::Rails::Example::ControllerExampleGroup,
7 # which supports running specs for Controllers in two modes, which
8 # represent the tension between the more granular testing common in TDD
9 # and the more high level testing built into rails. BDD sits somewhere
10 # in between: we want to a balance between specs that are close enough
11 # to the code to enable quick fault isolation and far enough away from
12 # the code to enable refactoring with minimal changes to the existing
13 # specs.
6d673c2 Made the following renames:
btakita authored
14 #
15 # == Isolation mode (default)
16 #
6853e88 @dchelimsky general cleanup
authored
17 # No dependencies on views because none are ever rendered. The benefit
18 # of this mode is that can spec the controller completely independent of
19 # the view, allowing that responsibility to be handled later, or by
20 # somebody else. Combined w/ separate view specs, this also provides
21 # better fault isolation.
6d673c2 Made the following renames:
btakita authored
22 #
23 # == Integration mode
24 #
25 # To run in this mode, include the +integrate_views+ declaration
26 # in your controller context:
27 #
28 # describe ThingController do
29 # integrate_views
30 # ...
31 #
6853e88 @dchelimsky general cleanup
authored
32 # In this mode, controller specs are run in the same way that rails
33 # functional tests run - one set of tests for both the controllers and
34 # the views. The benefit of this approach is that you get wider coverage
35 # from each spec. Experienced rails developers may find this an easier
36 # approach to begin with, however we encourage you to explore using the
37 # isolation mode and revel in its benefits.
6d673c2 Made the following renames:
btakita authored
38 #
39 # == Expecting Errors
40 #
e98e0c7 @bkeepers Add failing code examples to show that errors captured by rescue_from
bkeepers authored
41 # Rspec on Rails will raise errors that occur in controller actions and
42 # are not rescued or handeled with rescue_from.
6d673c2 Made the following renames:
btakita authored
43 #
44 class ControllerExampleGroup < FunctionalExampleGroup
45 class << self
c3321ac better examples (and a better fix) for http://rspec.lighthouseapp.com…
dchelimsky authored
46
6853e88 @dchelimsky general cleanup
authored
47 # Use integrate_views to instruct RSpec to render views in
48 # your controller examples in Integration mode.
6d673c2 Made the following renames:
btakita authored
49 #
50 # describe ThingController do
51 # integrate_views
52 # ...
53 #
6853e88 @dchelimsky general cleanup
authored
54 # See Spec::Rails::Example::ControllerExampleGroup for more
55 # information about Integration and Isolation modes.
4df2c72 @patmaddox got nested integrate_views working
patmaddox authored
56 def integrate_views(integrate_views = true)
57 @integrate_views = integrate_views
6d673c2 Made the following renames:
btakita authored
58 end
4df2c72 @patmaddox got nested integrate_views working
patmaddox authored
59
6d673c2 Made the following renames:
btakita authored
60 def integrate_views? # :nodoc:
61 @integrate_views
62 end
4df2c72 @patmaddox got nested integrate_views working
patmaddox authored
63
64 def inherited(klass) # :nodoc:
65 klass.integrate_views(integrate_views?)
5d114be @jferris Changed ControllerExampleGroup to use controller as the implicit subj…
jferris authored
66 klass.subject { controller }
4df2c72 @patmaddox got nested integrate_views working
patmaddox authored
67 super
68 end
08f32ac @zdennis fixed issue where ControllerExampleGroup wasn't respecting #controlle…
zdennis authored
69
6853e88 @dchelimsky general cleanup
authored
70 def set_description(*args) # :nodoc:
98f7d8a @dchelimsky cleaning up example group classes - remove controller_class_name
authored
71 super
08f32ac @zdennis fixed issue where ControllerExampleGroup wasn't respecting #controlle…
zdennis authored
72 if described_class && described_class.ancestors.include?(ActionController::Base)
73 controller_klass = if superclass.controller_class.ancestors.include?(ActionController::Base)
74 superclass.controller_class
75 else
76 described_class
77 end
78 tests controller_klass
98f7d8a @dchelimsky cleaning up example group classes - remove controller_class_name
authored
79 end
80 end
08f32ac @zdennis fixed issue where ControllerExampleGroup wasn't respecting #controlle…
zdennis authored
81
6853e88 @dchelimsky general cleanup
authored
82 # When you don't pass a controller to describe, like this:
83 #
84 # describe ThingsController do
85 #
86 # ... then you must provide a controller_name within the context of
6d673c2 Made the following renames:
btakita authored
87 # your controller specs:
88 #
89 # describe "ThingController" do
90 # controller_name :thing
91 # ...
92 def controller_name(name)
98f7d8a @dchelimsky cleaning up example group classes - remove controller_class_name
authored
93 tests "#{name}_controller".camelize.constantize
6d673c2 Made the following renames:
btakita authored
94 end
95 end
9fd1279 @dchelimsky Derive example group classes from the rails test cases
authored
96
6d673c2 Made the following renames:
btakita authored
97 before(:each) do
98 # Some Rails apps explicitly disable ActionMailer in environment.rb
99 if defined?(ActionMailer)
100 @deliveries = []
101 ActionMailer::Base.deliveries = @deliveries
102 end
103
104 unless @controller.class.ancestors.include?(ActionController::Base)
6853e88 @dchelimsky general cleanup
authored
105 Spec::Expectations.fail_with <<-MESSAGE
106 Controller specs need to know what controller is being specified. You can
107 indicate this by passing the controller to describe():
108
109 describe MyController do
110
111 or by declaring the controller's name
112
113 describe "a MyController" do
114 controller_name :my #invokes the MyController
115 end
116 MESSAGE
6d673c2 Made the following renames:
btakita authored
117 end
6853e88 @dchelimsky general cleanup
authored
118 @controller.extend ControllerInstanceMethods
d0d2afc @dchelimsky remove initialize method to reduce dependency on rspec-core internals
authored
119 @controller.integrate_views! if integrate_views?
6d673c2 Made the following renames:
btakita authored
120 @controller.session = session
121 end
122
123 attr_reader :response, :request, :controller
939d745 @dchelimsky Delegate route_for to assert_recognizes.
authored
124
d0d2afc @dchelimsky remove initialize method to reduce dependency on rspec-core internals
authored
125 def integrate_views?
126 @integrate_views || self.class.integrate_views?
127 end
128
40ce2c3 @dchelimsky Add bypass_rescue for controller specs
authored
129 # Bypasses any error rescues defined with rescue_from. Useful
130 # in cases in which you want to specify errors coming out of
131 # actions that might be caught by a rescue_from clause that is
132 # specified separately.
133 #
134 # Note that this will override the effect of rescue_action_in_public
135 def bypass_rescue
136 if ::Rails::VERSION::STRING >= '2.2'
137 def controller.rescue_action(exception)
138 raise exception
139 end
140 else
141 def controller.rescue_action_with_handler(exception)
142 raise exception
143 end
144 end
145 end
146
de90533 @dchelimsky refactor BEFORE running the full build, remember?
authored
147 protected
148
149 def _assigns_hash_proxy
6853e88 @dchelimsky general cleanup
authored
150 @_assigns_hash_proxy ||= AssignsHashProxy.new(self) {@response.template}
de90533 @dchelimsky refactor BEFORE running the full build, remember?
authored
151 end
152
153 private
b578d76 @dchelimsky clean up template extensions related to isolation
authored
154
155 module TemplateIsolationExtensions
156 def file_exists?(ignore); true; end
157
158 def render_file(*args)
159 @first_render ||= args[0] unless args[0] =~ /^layouts/
160 end
161
162 # Rails 2.2
163 def _pick_template(*args)
164 @_first_render ||= args[0] unless args[0] =~ /^layouts/
165 PickedTemplate.new
166 end
167
168 def render(*args)
7feca16 @dchelimsky FINALLY figured out how to restore ability for isolated controller specs
authored
169 if file = args.last[:file].instance_eval{@template_path}
170 record_render :file => file
171 elsif args.last[:inline]
172 super
173 elsif @_rendered
174 record_render(args[0])
175 else
176 super
177 end
6853e88 @dchelimsky general cleanup
authored
178 end
179
180 private
181
182 def record_render(opts)
183 (@_rendered[:template] ||= opts[:file]) if opts[:file]
184 (@_rendered[:partials][opts[:partial]] += 1) if opts[:partial]
185 end
186
187 # Returned by _pick_template when running controller examples in isolation mode.
188 class PickedTemplate
189 # Do nothing when running controller examples in isolation mode.
190 def render_template(*ignore_args); end
191 # Do nothing when running controller examples in isolation mode.
192 def render_partial(*ignore_args); end
b578d76 @dchelimsky clean up template extensions related to isolation
authored
193 end
194 end
6853e88 @dchelimsky general cleanup
authored
195
196 module ControllerInstanceMethods # :nodoc:
6d673c2 Made the following renames:
btakita authored
197 include Spec::Rails::Example::RenderObserver
198
b578d76 @dchelimsky clean up template extensions related to isolation
authored
199 # === render(options = nil, extra_options={}, &block)
6d673c2 Made the following renames:
btakita authored
200 #
201 # This gets added to the controller's singleton meta class,
202 # allowing Controller Examples to run in two modes, freely switching
6853e88 @dchelimsky general cleanup
authored
203 # from example group to example group.
b702dfb @dchelimsky support 2 arg version of ActionController::Base#render
authored
204 def render(options=nil, extra_options={}, &block)
6d673c2 Made the following renames:
btakita authored
205 unless block_given?
206 unless integrate_views?
b578d76 @dchelimsky clean up template extensions related to isolation
authored
207 @template.extend TemplateIsolationExtensions
6d673c2 Made the following renames:
btakita authored
208 end
209 end
210
42cb7ce Pass block to mock_proxy if and_yield is used in expect_render on a c…
dchelimsky authored
211 if matching_message_expectation_exists(options)
eb53fc0 @dchelimsky deprecate expect_render and stub_render in favor of rails-specific ex…
authored
212 render_proxy.render(options, &block)
6d673c2 Made the following renames:
btakita authored
213 @performed_render = true
214 else
f909c0d got rspec-rails working against edge rails (as of e48e77e0222292176cd…
David Chelimsky authored
215 if matching_stub_exists(options)
216 @performed_render = true
217 else
b702dfb @dchelimsky support 2 arg version of ActionController::Base#render
authored
218 super
6d673c2 Made the following renames:
btakita authored
219 end
220 end
221 end
42cb7ce Pass block to mock_proxy if and_yield is used in expect_render on a c…
dchelimsky authored
222
7feca16 @dchelimsky FINALLY figured out how to restore ability for isolated controller specs
authored
223 # Rails 2.3
224 def default_template(action_name = self.action_name)
225 if integrate_views?
226 super
227 else
228 begin
229 super
230 rescue ActionView::MissingTemplate
231 "#{self.class.name.sub(/Controller$/,'').underscore}/#{action_name}"
232 end
233 end
234 end
235
6d673c2 Made the following renames:
btakita authored
236 def response(&block)
237 # NOTE - we're setting @update for the assert_select_spec - kinda weird, huh?
238 @update = block
1857415 @dchelimsky add example specifying template extension (rails-2.3 only for now)
authored
239 super
6d673c2 Made the following renames:
btakita authored
240 end
241
242 def integrate_views!
243 @integrate_views = true
244 end
245
6853e88 @dchelimsky general cleanup
authored
246 private
1857415 @dchelimsky add example specifying template extension (rails-2.3 only for now)
authored
247
6d673c2 Made the following renames:
btakita authored
248 def integrate_views?
249 @integrate_views
250 end
6bbe80f @dchelimsky Decouple mock framework from global extensions used by rspec.
authored
251
252 def matching_message_expectation_exists(options)
6853e88 @dchelimsky general cleanup
authored
253 render_proxy.__send__(:__mock_proxy).__send__(:find_matching_expectation, :render, options)
6bbe80f @dchelimsky Decouple mock framework from global extensions used by rspec.
authored
254 end
255
256 def matching_stub_exists(options)
6853e88 @dchelimsky general cleanup
authored
257 render_proxy.__send__(:__mock_proxy).__send__(:find_matching_method_stub, :render, options)
6bbe80f @dchelimsky Decouple mock framework from global extensions used by rspec.
authored
258 end
259
6d673c2 Made the following renames:
btakita authored
260 end
261
262 Spec::Example::ExampleGroupFactory.register(:controller, self)
6853e88 @dchelimsky general cleanup
authored
263
e11c5b5 'should render_template' ignores layouts [#508 state:resolved]
David Chelimsky authored
264 end
6d673c2 Made the following renames:
btakita authored
265 end
266 end
267 end
Something went wrong with that request. Please try again.