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
@@ -1,23 +1,35 @@
|
|
1
1
|
require 'active_support/core_ext/module/aliasing'
|
2
2
|
require 'rspec/matchers/have'
|
3
3
|
|
4
|
-
module RSpec
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
module RSpec::Rails::Matchers
|
5
|
+
module HaveExtensions
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
#
|
10
|
+
# Enhances the failure message for `should have(n)` matchers
|
11
|
+
def failure_message_for_should_with_errors_on_extensions
|
12
|
+
return "expected #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}, got #{@actual}" if @collection_name == :errors_on
|
13
|
+
return "expected #{relativities[@relativity]}#{@expected} error on :#{@args[0]}, got #{@actual}" if @collection_name == :error_on
|
14
|
+
return failure_message_for_should_without_errors_on_extensions
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# Enhances the description for `should have(n)` matchers
|
20
|
+
def description_with_errors_on_extensions
|
21
|
+
return "have #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}" if @collection_name == :errors_on
|
22
|
+
return "have #{relativities[@relativity]}#{@expected} error on :#{@args[0]}" if @collection_name == :error_on
|
23
|
+
return description_without_errors_on_extensions
|
24
|
+
end
|
25
|
+
|
26
|
+
included do
|
27
|
+
alias_method_chain :failure_message_for_should, :errors_on_extensions
|
19
28
|
alias_method_chain :description, :errors_on_extensions
|
20
29
|
end
|
21
30
|
end
|
22
31
|
end
|
23
32
|
|
33
|
+
RSpec::Matchers::Have.class_eval do
|
34
|
+
include RSpec::Rails::Matchers::HaveExtensions
|
35
|
+
end
|
@@ -1,19 +1,38 @@
|
|
1
1
|
module RSpec::Rails::Matchers
|
2
2
|
module RedirectTo
|
3
|
-
|
3
|
+
class RedirectTo
|
4
|
+
include RSpec::Matchers::BaseMatcher
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def initialize(scope, expected)
|
7
|
+
super(expected)
|
8
|
+
@scope = scope
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
+
# @api private
|
12
|
+
def matches?(actual)
|
13
|
+
match_unless_raises ActiveSupport::TestCase::Assertion do
|
14
|
+
@scope.assert_redirected_to(expected)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def failure_message_for_should
|
11
20
|
rescued_exception.message
|
12
21
|
end
|
13
22
|
|
14
|
-
|
15
|
-
|
23
|
+
# @api private
|
24
|
+
def failure_message_for_should_not
|
25
|
+
"expected not to redirect to #{expected.inspect}, but did"
|
16
26
|
end
|
17
27
|
end
|
28
|
+
|
29
|
+
# Delegates to `assert_redirected_to`
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
#
|
33
|
+
# response.should redirect_to(:action => "new")
|
34
|
+
def redirect_to(target)
|
35
|
+
RedirectTo.new(self, target)
|
36
|
+
end
|
18
37
|
end
|
19
38
|
end
|
@@ -1,20 +1,39 @@
|
|
1
1
|
module RSpec::Rails::Matchers
|
2
2
|
module RenderTemplate
|
3
|
-
|
3
|
+
class RenderTemplateMatcher
|
4
|
+
include RSpec::Matchers::BaseMatcher
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(scope, expected, message=nil)
|
7
|
+
super(Symbol === expected ? expected.to_s : expected)
|
8
|
+
@message = message
|
9
|
+
@scope = scope
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
+
# @api private
|
13
|
+
def matches?(*)
|
14
|
+
match_unless_raises ActiveSupport::TestCase::Assertion do
|
15
|
+
@scope.assert_template expected, @message
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def failure_message_for_should
|
12
21
|
rescued_exception.message
|
13
22
|
end
|
14
23
|
|
15
|
-
|
16
|
-
|
24
|
+
# @api private
|
25
|
+
def failure_message_for_should_not
|
26
|
+
"expected not to render #{expected.inspect}, but did"
|
17
27
|
end
|
18
28
|
end
|
29
|
+
|
30
|
+
# Delegates to `assert_template`
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
#
|
34
|
+
# response.should render_template("new")
|
35
|
+
def render_template(options, message=nil)
|
36
|
+
RenderTemplateMatcher.new(self, options, message)
|
37
|
+
end
|
19
38
|
end
|
20
39
|
end
|
@@ -2,50 +2,98 @@ module RSpec::Rails::Matchers
|
|
2
2
|
module RoutingMatchers
|
3
3
|
extend RSpec::Matchers::DSL
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
class RouteToMatcher
|
6
|
+
include RSpec::Matchers::BaseMatcher
|
7
|
+
|
8
|
+
def initialize(scope, *expected)
|
9
|
+
@scope = scope
|
10
|
+
@expected_options = expected[1] || {}
|
11
|
+
if Hash === expected[0]
|
12
|
+
@expected_options.merge!(expected[0])
|
13
|
+
else
|
14
|
+
controller, action = expected[0].split('#')
|
15
|
+
@expected_options.merge!(:controller => controller, :action => action)
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
# @api private
|
20
|
+
def matches?(verb_to_path_map)
|
21
|
+
match_unless_raises ActiveSupport::TestCase::Assertion do
|
22
|
+
path, query = *verb_to_path_map.values.first.split('?')
|
23
|
+
@scope.assert_recognizes(
|
24
|
+
@expected_options,
|
25
|
+
{:method => verb_to_path_map.keys.first, :path => path},
|
26
|
+
Rack::Utils::parse_query(query)
|
27
|
+
)
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
|
-
|
31
|
+
# @api private
|
32
|
+
def failure_message_for_should
|
24
33
|
rescued_exception.message
|
25
34
|
end
|
35
|
+
end
|
26
36
|
|
37
|
+
# Delegates to `assert_recognizes`. Supports short-hand controller/action
|
38
|
+
# declarations (e.g. `"controller#action"`).
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
#
|
42
|
+
# { :get => "/things/special" }.should route_to(
|
43
|
+
# :controller => "things",
|
44
|
+
# :action => "special"
|
45
|
+
# )
|
46
|
+
#
|
47
|
+
# { :get => "/things/special" }.should route_to("things#special")
|
48
|
+
#
|
49
|
+
# @see http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes
|
50
|
+
def route_to(*expected)
|
51
|
+
RouteToMatcher.new(self, *expected)
|
27
52
|
end
|
28
53
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
54
|
+
class BeRoutableMatcher
|
55
|
+
include RSpec::Matchers::BaseMatcher
|
56
|
+
|
57
|
+
def initialize(scope)
|
58
|
+
@scope = scope
|
59
|
+
end
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
def matches?(path)
|
63
|
+
super(path)
|
64
|
+
match_unless_raises ActionController::RoutingError do
|
65
|
+
@routing_options = @scope.routes.recognize_path(
|
66
|
+
path.values.first, :method => path.keys.first
|
67
|
+
)
|
68
|
+
end
|
34
69
|
end
|
35
70
|
|
36
|
-
|
37
|
-
|
71
|
+
# @api private
|
72
|
+
def failure_message_for_should_not
|
73
|
+
"expected #{actual.inspect} not to be routable, but it routes to #{@routing_options.inspect}"
|
38
74
|
end
|
39
75
|
end
|
40
76
|
|
41
|
-
|
77
|
+
# Passes if the route expression is recognized by the Rails router based on
|
78
|
+
# the declarations in `config/routes.rb`. Delegates to
|
79
|
+
# `RouteSet#recognize_path`.
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
#
|
83
|
+
# You can use route helpers provided by rspec-rails.
|
84
|
+
# {:get => "/a/path"}.should be_routable
|
85
|
+
# {:post => "/another/path"}.should be_routable
|
86
|
+
# {:put => "/yet/another/path"}.should_not be_routable
|
87
|
+
def be_routable
|
88
|
+
BeRoutableMatcher.new(self)
|
89
|
+
end
|
42
90
|
|
91
|
+
module RouteHelpers
|
43
92
|
%w(get post put delete options head).each do |method|
|
44
93
|
define_method method do |path|
|
45
94
|
{ method.to_sym => path }
|
46
95
|
end
|
47
96
|
end
|
48
|
-
|
49
97
|
end
|
50
98
|
end
|
51
99
|
end
|
data/lib/rspec/rails/mocks.rb
CHANGED
@@ -9,7 +9,7 @@ module RSpec
|
|
9
9
|
module Mocks
|
10
10
|
|
11
11
|
module ActiveModelInstanceMethods
|
12
|
-
# Stubs
|
12
|
+
# Stubs `persisted?` to return false and `id` to return nil
|
13
13
|
# @return self
|
14
14
|
def as_new_record
|
15
15
|
self.stub(:persisted?) { false }
|
@@ -30,7 +30,7 @@ module RSpec
|
|
30
30
|
end
|
31
31
|
|
32
32
|
module ActiveRecordInstanceMethods
|
33
|
-
# Stubs
|
33
|
+
# Stubs `persisted?` to return `false` and `id` to return `nil`.
|
34
34
|
def destroy
|
35
35
|
self.stub(:persisted?) { false }
|
36
36
|
self.stub(:id) { nil }
|
@@ -41,15 +41,15 @@ module RSpec
|
|
41
41
|
send(key)
|
42
42
|
end
|
43
43
|
|
44
|
-
# Returns the opposite of
|
44
|
+
# Returns the opposite of `persisted?`
|
45
45
|
def new_record?
|
46
46
|
!persisted?
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# Creates a test double representing
|
50
|
+
# Creates a test double representing `string_or_model_class` with common
|
51
51
|
# ActiveModel methods stubbed out. Additional methods may be easily
|
52
|
-
# stubbed (via add_stubs) if
|
52
|
+
# stubbed (via add_stubs) if `stubs` is passed. This is most useful for
|
53
53
|
# impersonating models that don't exist yet.
|
54
54
|
#
|
55
55
|
# NOTE that only ActiveModel's methods, plus <tt>new_record?</tt>, are
|
@@ -59,7 +59,7 @@ module RSpec
|
|
59
59
|
# ActiveModel API (which declares <tt>persisted?</tt>, not
|
60
60
|
# <tt>new_record?</tt>).
|
61
61
|
#
|
62
|
-
#
|
62
|
+
# `string_or_model_class` can be any of:
|
63
63
|
#
|
64
64
|
# * A String representing a Class that does not exist
|
65
65
|
# * A String representing a Class that extends ActiveModel::Naming
|
@@ -90,20 +90,22 @@ EOM
|
|
90
90
|
end
|
91
91
|
|
92
92
|
stubs = stubs.reverse_merge(:id => next_id)
|
93
|
-
stubs = stubs.reverse_merge(:persisted? => !!stubs[:id]
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
stubs = stubs.reverse_merge(:persisted? => !!stubs[:id],
|
94
|
+
:destroyed? => false,
|
95
|
+
:marked_for_destruction? => false,
|
96
|
+
:blank? => false)
|
97
97
|
|
98
98
|
mock("#{model_class.name}_#{stubs[:id]}", stubs).tap do |m|
|
99
|
-
m.
|
100
|
-
|
101
|
-
|
99
|
+
m.singleton_class.class_eval do
|
100
|
+
include ActiveModelInstanceMethods
|
101
|
+
include ActiveRecordInstanceMethods if defined?(ActiveRecord)
|
102
|
+
include ActiveModel::Conversion
|
103
|
+
include ActiveModel::Validations
|
104
|
+
end
|
102
105
|
if defined?(ActiveRecord)
|
103
|
-
m.extend ActiveRecordInstanceMethods
|
104
106
|
[:save, :update_attributes].each do |key|
|
105
107
|
if stubs[key] == false
|
106
|
-
m.errors.stub(:empty?
|
108
|
+
m.errors.stub(:empty? => false)
|
107
109
|
end
|
108
110
|
end
|
109
111
|
end
|
@@ -119,11 +121,19 @@ EOM
|
|
119
121
|
def @object.instance_of?(other)
|
120
122
|
other == #{model_class}
|
121
123
|
end unless #{stubs.has_key?(:instance_of?)}
|
122
|
-
|
124
|
+
|
125
|
+
def @object.__model_class_has_column?(method_name)
|
126
|
+
#{model_class}.respond_to?(:column_names) && #{model_class}.column_names.include?(method_name.to_s)
|
127
|
+
end
|
128
|
+
|
123
129
|
def @object.respond_to?(method_name, include_private=false)
|
124
|
-
|
130
|
+
__model_class_has_column?(method_name) ? true : super
|
125
131
|
end unless #{stubs.has_key?(:respond_to?)}
|
126
132
|
|
133
|
+
def @object.method_missing(m, *a, &b)
|
134
|
+
respond_to?(m) ? nil : super
|
135
|
+
end
|
136
|
+
|
127
137
|
def @object.class
|
128
138
|
#{model_class}
|
129
139
|
end unless #{stubs.has_key?(:class)}
|
@@ -137,27 +147,27 @@ EOM
|
|
137
147
|
end
|
138
148
|
|
139
149
|
module ActiveModelStubExtensions
|
140
|
-
# Stubs
|
150
|
+
# Stubs `persisted` to return false and `id` to return nil
|
141
151
|
def as_new_record
|
142
152
|
self.stub(:persisted?) { false }
|
143
153
|
self.stub(:id) { nil }
|
144
154
|
self
|
145
155
|
end
|
146
156
|
|
147
|
-
# Returns
|
157
|
+
# Returns `true` by default. Override with a stub.
|
148
158
|
def persisted?
|
149
159
|
true
|
150
160
|
end
|
151
161
|
end
|
152
162
|
|
153
163
|
module ActiveRecordStubExtensions
|
154
|
-
# Stubs
|
164
|
+
# Stubs `id` (or other primary key method) to return nil
|
155
165
|
def as_new_record
|
156
166
|
self.__send__("#{self.class.primary_key}=", nil)
|
157
167
|
super
|
158
168
|
end
|
159
169
|
|
160
|
-
# Returns the opposite of
|
170
|
+
# Returns the opposite of `persisted?`.
|
161
171
|
def new_record?
|
162
172
|
!persisted?
|
163
173
|
end
|
@@ -169,11 +179,11 @@ EOM
|
|
169
179
|
end
|
170
180
|
end
|
171
181
|
|
172
|
-
# Creates an instance of
|
173
|
-
# generated value that is unique to each object.. If
|
174
|
-
#
|
182
|
+
# Creates an instance of `Model` with `to_param` stubbed using a
|
183
|
+
# generated value that is unique to each object.. If `Model` is an
|
184
|
+
# `ActiveRecord` model, it is prohibited from accessing the database*.
|
175
185
|
#
|
176
|
-
# For each key in
|
186
|
+
# For each key in `hash_of_stubs`, if the model has a matching attribute
|
177
187
|
# (determined by asking it) are simply assigned the submitted values. If
|
178
188
|
# the model does not have a matching attribute, the key/value pair is
|
179
189
|
# assigned as a stub return value using RSpec's mocking/stubbing
|
@@ -181,23 +191,21 @@ EOM
|
|
181
191
|
#
|
182
192
|
# <tt>persisted?</tt> is overridden to return the result of !id.nil?
|
183
193
|
# This means that by default persisted? will return true. If you want
|
184
|
-
# the object to behave as a new record, sending it
|
194
|
+
# the object to behave as a new record, sending it `as_new_record` will
|
185
195
|
# set the id to nil. You can also explicitly set :id => nil, in which
|
186
|
-
# case persisted? will return false, but using
|
196
|
+
# case persisted? will return false, but using `as_new_record` makes the
|
187
197
|
# example a bit more descriptive.
|
188
198
|
#
|
189
199
|
# While you can use stub_model in any example (model, view, controller,
|
190
200
|
# helper), it is especially useful in view examples, which are
|
191
201
|
# inherently more state-based than interaction-based.
|
192
202
|
#
|
193
|
-
#
|
203
|
+
# @example
|
194
204
|
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
# person.first_name = "David"
|
200
|
-
# end
|
205
|
+
# stub_model(Person)
|
206
|
+
# stub_model(Person).as_new_record
|
207
|
+
# stub_model(Person, :to_param => 37)
|
208
|
+
# stub_model(Person) {|person| person.first_name = "David"}
|
201
209
|
def stub_model(model_class, stubs={})
|
202
210
|
model_class.new.tap do |m|
|
203
211
|
m.extend ActiveModelStubExtensions
|