rspec-rails 2.0.0.beta.8 → 2.0.0.beta.9.1
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/README.markdown +82 -27
- data/Rakefile +7 -7
- data/Upgrade.markdown +12 -0
- data/VERSION +1 -1
- data/autotest/discover.rb +1 -0
- data/cucumber.yml +3 -0
- data/example_app_template.rb +2 -2
- data/features/controller_specs/do_not_render_views.feature +61 -0
- data/features/controller_specs/readers.feature +18 -0
- data/features/controller_specs/render_views.feature +53 -0
- data/features/model_specs/errors_on.feature +32 -0
- data/features/model_specs/transactional_examples.feature +2 -2
- data/features/view_specs/view_spec.feature +102 -1
- data/lib/autotest/rails_rspec2.rb +1 -1
- data/lib/generators/rspec/helper/helper_generator.rb +1 -0
- data/lib/generators/rspec/helper/templates/helper_spec.rb +3 -3
- data/lib/generators/rspec/install/install_generator.rb +7 -7
- data/lib/generators/rspec/scaffold/scaffold_generator.rb +10 -1
- data/lib/generators/rspec/scaffold/templates/edit_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/index_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/show_spec.rb +2 -2
- data/lib/rspec-rails.rb +12 -0
- data/lib/rspec/rails.rb +8 -0
- data/lib/rspec/rails/adapters.rb +12 -8
- data/lib/rspec/rails/example.rb +1 -0
- data/lib/rspec/rails/example/controller_example_group.rb +13 -12
- data/lib/rspec/rails/example/helper_example_group.rb +43 -0
- data/lib/rspec/rails/example/mailer_example_group.rb +10 -5
- data/lib/rspec/rails/example/request_example_group.rb +7 -7
- data/lib/rspec/rails/example/view_example_group.rb +44 -62
- data/lib/rspec/rails/extensions.rb +1 -0
- data/lib/rspec/rails/extensions/active_record/base.rb +46 -0
- data/lib/rspec/rails/matchers.rb +28 -3
- data/lib/rspec/rails/mocks.rb +3 -3
- data/lib/rspec/rails/monkey.rb +1 -0
- data/lib/rspec/rails/monkey/action_controller/test_case.rb +153 -145
- data/lib/rspec/rails/monkey/action_view/test_case.rb +201 -0
- data/lib/rspec/rails/null_resolver.rb +10 -0
- data/lib/{generators/rspec/install/templates/lib → rspec/rails}/tasks/rspec.rake +4 -5
- data/lib/rspec/rails/transactional_database_support.rb +4 -6
- data/lib/rspec/rails/version.rb +1 -1
- data/lib/rspec/rails/view_assigns.rb +28 -0
- data/lib/rspec/rails/view_rendering.rb +33 -0
- data/rspec-rails.gemspec +41 -11
- data/spec/rspec/rails/example/controller_example_group_spec.rb +11 -0
- data/spec/rspec/rails/example/helper_example_group_spec.rb +20 -0
- data/spec/rspec/rails/example/mailer_example_group_spec.rb +11 -0
- data/spec/rspec/rails/example/request_example_group_spec.rb +11 -0
- data/spec/rspec/rails/example/view_example_group_spec.rb +75 -0
- data/spec/rspec/rails/example/view_rendering_spec.rb +68 -0
- data/spec/rspec/rails/matchers/errors_on_spec.rb +38 -0
- data/spec/rspec/rails/mocks/ar_classes.rb +1 -1
- data/spec/rspec/rails/mocks/mock_model_spec.rb +88 -65
- data/spec/rspec/rails/mocks/stub_model_spec.rb +1 -1
- data/spec/rspec/rails/transactional_database_support_spec.rb +2 -2
- data/spec/spec_helper.rb +18 -2
- data/spec/support/helpers.rb +20 -0
- data/specs.watchr +10 -10
- data/templates/generate_stuff.rb +3 -1
- metadata +40 -9
@@ -0,0 +1 @@
|
|
1
|
+
require 'rspec/rails/extensions/active_record/base'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
if defined?(ActiveRecord::Base)
|
2
|
+
module RSpec
|
3
|
+
module Rails
|
4
|
+
module Extensions
|
5
|
+
module ActiveRecord
|
6
|
+
module ClassMethods
|
7
|
+
# :call-seq:
|
8
|
+
# ModelClass.should have(:no).records
|
9
|
+
# ModelClass.should have(1).record
|
10
|
+
# ModelClass.should have(n).records
|
11
|
+
#
|
12
|
+
# Extension to enhance <tt>should have</tt> on AR Model classes
|
13
|
+
def records
|
14
|
+
find(:all)
|
15
|
+
end
|
16
|
+
alias :record :records
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods
|
20
|
+
# :call-seq:
|
21
|
+
# model.should have(:no).errors_on(:attribute)
|
22
|
+
# model.should have(1).error_on(:attribute)
|
23
|
+
# model.should have(n).errors_on(:attribute)
|
24
|
+
#
|
25
|
+
# Extension to enhance <tt>should have</tt> on AR Model instances.
|
26
|
+
# Calls model.valid? in order to prepare the object's errors
|
27
|
+
# object.
|
28
|
+
def errors_on(attribute)
|
29
|
+
self.valid?
|
30
|
+
[self.errors[attribute]].flatten.compact
|
31
|
+
end
|
32
|
+
alias :error_on :errors_on
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module ActiveRecord #:nodoc:
|
40
|
+
class Base
|
41
|
+
extend RSpec::Rails::Extensions::ActiveRecord::ClassMethods
|
42
|
+
include RSpec::Rails::Extensions::ActiveRecord::InstanceMethods
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/lib/rspec/rails/matchers.rb
CHANGED
@@ -17,21 +17,46 @@ rescue LoadError
|
|
17
17
|
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
RSpec::Matchers.define :redirect_to do |destination|
|
21
21
|
match_unless_raises Test::Unit::AssertionFailedError do |_|
|
22
22
|
assert_redirected_to destination
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
RSpec::Matchers.define :render_template do |options, message|
|
27
27
|
match_unless_raises Test::Unit::AssertionFailedError do |_|
|
28
28
|
options = options.to_s if Symbol === options
|
29
29
|
assert_template options, message
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
RSpec::Matchers.define :be_a_new do |model_klass|
|
34
34
|
match do |actual|
|
35
35
|
model_klass === actual && actual.new_record?
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
require 'rspec/matchers/have'
|
40
|
+
|
41
|
+
module RSpec #:nodoc:
|
42
|
+
module Matchers #:nodoc:
|
43
|
+
class Have #:nodoc:
|
44
|
+
|
45
|
+
def failure_message_for_should_with_errors_on_extensions
|
46
|
+
return "expected #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}, got #{@actual}" if @collection_name == :errors_on
|
47
|
+
return "expected #{relativities[@relativity]}#{@expected} error on :#{@args[0]}, got #{@actual}" if @collection_name == :error_on
|
48
|
+
return failure_message_for_should_without_errors_on_extensions
|
49
|
+
end
|
50
|
+
alias_method_chain :failure_message_for_should, :errors_on_extensions
|
51
|
+
|
52
|
+
def description_with_errors_on_extensions
|
53
|
+
return "have #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}" if @collection_name == :errors_on
|
54
|
+
return "have #{relativities[@relativity]}#{@expected} error on :#{@args[0]}" if @collection_name == :error_on
|
55
|
+
return description_without_errors_on_extensions
|
56
|
+
end
|
57
|
+
alias_method_chain :description, :errors_on_extensions
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/lib/rspec/rails/mocks.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module RSpec
|
2
2
|
module Rails
|
3
3
|
|
4
4
|
class IllegalDataAccessException < StandardError; end
|
@@ -140,6 +140,6 @@ module Rspec
|
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
-
|
144
|
-
c.include
|
143
|
+
RSpec.configure do |c|
|
144
|
+
c.include RSpec::Rails::Mocks
|
145
145
|
end
|
data/lib/rspec/rails/monkey.rb
CHANGED
@@ -7,193 +7,201 @@ module ActionController
|
|
7
7
|
# Once 3.0.0.rc.1 comes out, we can remove it.
|
8
8
|
module TemplateAssertions
|
9
9
|
def teardown_subscriptions
|
10
|
+
# rails-3.0.0.beta.3
|
10
11
|
ActiveSupport::Notifications.unsubscribe("action_view.render_template")
|
11
12
|
ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
|
13
|
+
|
14
|
+
# as of 731d4392e478ff5526b595074d9caa999da8bd0c
|
15
|
+
ActiveSupport::Notifications.unsubscribe("render_template.action_view")
|
16
|
+
ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
15
|
-
#
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
# This has been merged to rails HEAD after the 3.0.0.beta.3 release (see
|
21
|
+
# https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4474).
|
22
|
+
# Once 3.0.0.rc.1 comes out, we can remove it.
|
23
|
+
unless defined?(ActionController::TestCase::Behavior)
|
24
|
+
class TestCase < ActiveSupport::TestCase
|
25
|
+
module Behavior
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
include ActionDispatch::TestProcess
|
28
|
+
|
29
|
+
attr_reader :response, :request
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
|
33
|
+
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
34
|
+
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
|
35
|
+
def tests(controller_class)
|
36
|
+
self.controller_class = controller_class
|
37
|
+
end
|
38
|
+
|
39
|
+
def controller_class=(new_class)
|
40
|
+
prepare_controller_class(new_class) if new_class
|
41
|
+
write_inheritable_attribute(:controller_class, new_class)
|
42
|
+
end
|
43
|
+
|
44
|
+
def controller_class
|
45
|
+
if current_controller_class = read_inheritable_attribute(:controller_class)
|
46
|
+
current_controller_class
|
47
|
+
else
|
48
|
+
self.controller_class = determine_default_controller_class(name)
|
49
|
+
end
|
50
|
+
end
|
21
51
|
|
22
|
-
|
52
|
+
def determine_default_controller_class(name)
|
53
|
+
name.sub(/Test$/, '').constantize
|
54
|
+
rescue NameError
|
55
|
+
nil
|
56
|
+
end
|
23
57
|
|
24
|
-
|
58
|
+
def prepare_controller_class(new_class)
|
59
|
+
new_class.send :include, ActionController::TestCase::RaiseActionExceptions
|
60
|
+
end
|
25
61
|
|
26
|
-
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
27
|
-
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
|
28
|
-
def tests(controller_class)
|
29
|
-
self.controller_class = controller_class
|
30
62
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
63
|
+
|
64
|
+
# Executes a request simulating GET HTTP method and set/volley the response
|
65
|
+
def get(action, parameters = nil, session = nil, flash = nil)
|
66
|
+
process(action, parameters, session, flash, "GET")
|
35
67
|
end
|
36
68
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
else
|
41
|
-
self.controller_class = determine_default_controller_class(name)
|
42
|
-
end
|
69
|
+
# Executes a request simulating POST HTTP method and set/volley the response
|
70
|
+
def post(action, parameters = nil, session = nil, flash = nil)
|
71
|
+
process(action, parameters, session, flash, "POST")
|
43
72
|
end
|
44
73
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
nil
|
74
|
+
# Executes a request simulating PUT HTTP method and set/volley the response
|
75
|
+
def put(action, parameters = nil, session = nil, flash = nil)
|
76
|
+
process(action, parameters, session, flash, "PUT")
|
49
77
|
end
|
50
78
|
|
51
|
-
|
52
|
-
|
79
|
+
# Executes a request simulating DELETE HTTP method and set/volley the response
|
80
|
+
def delete(action, parameters = nil, session = nil, flash = nil)
|
81
|
+
process(action, parameters, session, flash, "DELETE")
|
53
82
|
end
|
54
83
|
|
55
|
-
|
84
|
+
# Executes a request simulating HEAD HTTP method and set/volley the response
|
85
|
+
def head(action, parameters = nil, session = nil, flash = nil)
|
86
|
+
process(action, parameters, session, flash, "HEAD")
|
87
|
+
end
|
56
88
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
89
|
+
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
|
90
|
+
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
91
|
+
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
92
|
+
returning __send__(request_method, action, parameters, session, flash) do
|
93
|
+
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
94
|
+
@request.env.delete 'HTTP_ACCEPT'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
alias xhr :xml_http_request
|
98
|
+
|
99
|
+
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
|
100
|
+
# Sanity check for required instance variables so we can give an
|
101
|
+
# understandable error message.
|
102
|
+
%w(@routes @controller @request @response).each do |iv_name|
|
103
|
+
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
|
104
|
+
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
105
|
+
end
|
106
|
+
end
|
61
107
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
108
|
+
@request.recycle!
|
109
|
+
@response.recycle!
|
110
|
+
@controller.response_body = nil
|
111
|
+
@controller.formats = nil
|
112
|
+
@controller.params = nil
|
66
113
|
|
67
|
-
|
68
|
-
|
69
|
-
process(action, parameters, session, flash, "PUT")
|
70
|
-
end
|
114
|
+
@html_document = nil
|
115
|
+
@request.env['REQUEST_METHOD'] = http_method
|
71
116
|
|
72
|
-
|
73
|
-
|
74
|
-
process(action, parameters, session, flash, "DELETE")
|
75
|
-
end
|
117
|
+
parameters ||= {}
|
118
|
+
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
|
76
119
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
120
|
+
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
121
|
+
@request.session["flash"] = @request.flash.update(flash || {})
|
122
|
+
@request.session["flash"].sweep
|
81
123
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
@request
|
87
|
-
@request.
|
88
|
-
|
89
|
-
end
|
90
|
-
alias xhr :xml_http_request
|
91
|
-
|
92
|
-
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
|
93
|
-
# Sanity check for required instance variables so we can give an
|
94
|
-
# understandable error message.
|
95
|
-
%w(@routes @controller @request @response).each do |iv_name|
|
96
|
-
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
|
97
|
-
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
98
|
-
end
|
124
|
+
@controller.request = @request
|
125
|
+
@controller.params.merge!(parameters)
|
126
|
+
build_request_uri(action, parameters)
|
127
|
+
Base.class_eval { include Testing }
|
128
|
+
@controller.process_with_new_base_test(@request, @response)
|
129
|
+
@request.session.delete('flash') if @request.session['flash'].blank?
|
130
|
+
@response
|
99
131
|
end
|
100
132
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
@controller.formats = nil
|
105
|
-
@controller.params = nil
|
106
|
-
|
107
|
-
@html_document = nil
|
108
|
-
@request.env['REQUEST_METHOD'] = http_method
|
109
|
-
|
110
|
-
parameters ||= {}
|
111
|
-
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
|
112
|
-
|
113
|
-
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
114
|
-
@request.session["flash"] = @request.flash.update(flash || {})
|
115
|
-
@request.session["flash"].sweep
|
116
|
-
|
117
|
-
@controller.request = @request
|
118
|
-
@controller.params.merge!(parameters)
|
119
|
-
build_request_uri(action, parameters)
|
120
|
-
Base.class_eval { include Testing }
|
121
|
-
@controller.process_with_new_base_test(@request, @response)
|
122
|
-
@request.session.delete('flash') if @request.session['flash'].blank?
|
123
|
-
@response
|
124
|
-
end
|
133
|
+
def setup_controller_request_and_response
|
134
|
+
@request = TestRequest.new
|
135
|
+
@response = TestResponse.new
|
125
136
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
if klass = self.class.controller_class
|
131
|
-
@controller ||= klass.new rescue nil
|
132
|
-
end
|
137
|
+
if klass = self.class.controller_class
|
138
|
+
@controller ||= klass.new rescue nil
|
139
|
+
end
|
133
140
|
|
134
|
-
|
141
|
+
@request.env.delete('PATH_INFO')
|
135
142
|
|
136
|
-
|
137
|
-
|
138
|
-
|
143
|
+
if @controller
|
144
|
+
@controller.request = @request
|
145
|
+
@controller.params = {}
|
146
|
+
end
|
139
147
|
end
|
140
|
-
end
|
141
148
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
149
|
+
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
|
150
|
+
def rescue_action_in_public!
|
151
|
+
@request.remote_addr = '208.77.188.166' # example.com
|
152
|
+
end
|
146
153
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
154
|
+
included do
|
155
|
+
include ActionController::TemplateAssertions
|
156
|
+
include ActionDispatch::Assertions
|
157
|
+
setup :setup_controller_request_and_response
|
158
|
+
end
|
152
159
|
|
153
|
-
|
160
|
+
private
|
154
161
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
162
|
+
def build_request_uri(action, parameters)
|
163
|
+
unless @request.env["PATH_INFO"]
|
164
|
+
options = @controller.__send__(:url_options).merge(parameters)
|
165
|
+
options.update(
|
166
|
+
:only_path => true,
|
167
|
+
:action => action,
|
168
|
+
:relative_url_root => nil,
|
169
|
+
:_path_segments => @request.symbolized_path_parameters)
|
163
170
|
|
164
|
-
|
171
|
+
url, query_string = @routes.url_for(options).split("?", 2)
|
165
172
|
|
166
|
-
|
167
|
-
|
168
|
-
|
173
|
+
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
|
174
|
+
@request.env["PATH_INFO"] = url
|
175
|
+
@request.env["QUERY_STRING"] = query_string || ""
|
176
|
+
end
|
169
177
|
end
|
170
178
|
end
|
171
|
-
end
|
172
179
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
180
|
+
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
|
181
|
+
# (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
|
182
|
+
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
|
183
|
+
# than 0.0.0.0.
|
184
|
+
#
|
185
|
+
# The exception is stored in the exception accessor for further inspection.
|
186
|
+
module RaiseActionExceptions
|
187
|
+
def self.included(base)
|
188
|
+
base.class_eval do
|
189
|
+
attr_accessor :exception
|
190
|
+
protected :exception, :exception=
|
191
|
+
end
|
184
192
|
end
|
185
|
-
end
|
186
193
|
|
187
|
-
|
188
|
-
|
189
|
-
|
194
|
+
protected
|
195
|
+
def rescue_action_without_handler(e)
|
196
|
+
self.exception = e
|
190
197
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
198
|
+
if request.remote_addr == "0.0.0.0"
|
199
|
+
raise(e)
|
200
|
+
else
|
201
|
+
super(e)
|
202
|
+
end
|
195
203
|
end
|
196
|
-
|
204
|
+
end
|
197
205
|
end
|
198
206
|
end
|
199
207
|
end
|