/
controller_example_group.rb
185 lines (172 loc) · 5.55 KB
/
controller_example_group.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
RSpec.configure do |config|
config.add_setting :infer_base_class_for_anonymous_controllers, :default => false
end
module RSpec::Rails
# Extends ActionController::TestCase::Behavior to work with RSpec.
#
# == Examples
#
# == with stubs
#
# describe WidgetsController do
# describe "GET index" do
# it "assigns all widgets to @widgets" do
# widget = stub_model(Widget)
# Widget.stub(:all) { widget }
# get :index
# assigns(:widgets).should eq([widget])
# end
# end
# end
#
# === with a factory
#
# describe WidgetsController do
# describe "GET index" do
# it "assigns all widgets to @widgets" do
# widget = Factory(:widget)
# get :index
# assigns(:widgets).should eq([widget])
# end
# end
# end
#
# === with fixtures
#
# describe WidgetsController do
# describe "GET index" do
# fixtures :widgets
#
# it "assigns all widgets to @widgets" do
# get :index
# assigns(:widgets).should eq(Widget.all)
# end
# end
# end
#
# == Matchers
#
# In addition to the stock matchers from rspec-expectations, controller
# specs add these matchers, which delegate to rails' assertions:
#
# response.should render_template(*args)
# => delegates to assert_template(*args)
#
# response.should redirect_to(destination)
# => delegates to assert_redirected_to(destination)
#
# == Isolation from views
#
# RSpec's preferred approach to spec'ing controller behaviour is to isolate
# the controller from its collaborators. By default, therefore, controller
# example groups do not render the views in your app. Due to the way Rails
# searches for view templates, the template still needs to exist, but it
# won't actually be loaded.
#
# NOTE that this is different from rspec-rails-1 with rails-2, which did not
# require the presence of the file at all. Due to changes in rails-3, this
# was no longer feasible in rspec-rails-2.
#
# == View rendering
#
# If you prefer a more integrated approach, similar to that of Rails'
# functional tests, you can tell controller groups to render the views in the
# app with the +render_views+ declaration:
#
# describe WidgetsController do
# render_views
# ...
#
module ControllerExampleGroup
extend ActiveSupport::Concern
include RSpec::Rails::RailsExampleGroup
include ActionController::TestCase::Behavior
include RSpec::Rails::ViewRendering
include RSpec::Rails::Matchers::RedirectTo
include RSpec::Rails::Matchers::RenderTemplate
include RSpec::Rails::Matchers::RoutingMatchers
module ClassMethods
def controller_class
describes
end
# Supports a simple DSL for specifying behaviour of
# ApplicationController. Creates an anonymous subclass of
# ApplicationController and evals the +body+ in that context. Also sets
# up implicit routes for this controller, that are separate from those
# defined in <tt>config/routes.rb</tt>.
#
# == Examples
#
# describe ApplicationController do
# controller do
# def index
# raise ApplicationController::AccessDenied
# end
# end
#
# describe "handling AccessDenied exceptions" do
# it "redirects to the /401.html page" do
# get :index
# response.should redirect_to("/401.html")
# end
# end
# end
#
# If you would like to spec a subclass of ApplicationController, call
# controller like so:
#
# controller(ApplicationControllerSubclass) do
# # ....
# end
#
# NOTICE: Due to Ruby 1.8 scoping rules in anoymous subclasses, constants
# defined in +ApplicationController+ must be fully qualified (e.g.
# ApplicationController::AccessDenied) in the block passed to the
# +controller+ method. Any instance methods, filters, etc, that are
# defined in +ApplicationController+, however, are accessible from within
# the block.
def controller(base_class = nil, &body)
base_class ||= RSpec.configuration.infer_base_class_for_anonymous_controllers? ?
controller_class :
ApplicationController
metadata[:example_group][:describes] = Class.new(base_class, &body)
metadata[:example_group][:describes].singleton_class.class_eval do
def name; "AnonymousController" end
end
before do
@orig_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new
@routes.draw { resources :anonymous }
end
after do
@routes, @orig_routes = @orig_routes, nil
end
end
end
module InstanceMethods
attr_reader :controller, :routes
module BypassRescue
def rescue_with_handler(exception)
raise exception
end
end
def bypass_rescue
controller.extend(BypassRescue)
end
def method_missing(method, *args, &block)
if @orig_routes && @orig_routes.named_routes.helpers.include?(method)
controller.send(method, *args, &block)
else
super
end
end
end
included do
subject { controller }
metadata[:type] = :controller
before do
@routes = ::Rails.application.routes
ActionController::Base.allow_forgery_protection = false
end
end
end
end