remarkable_rails 3.1.0 → 3.1.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/CHANGELOG +25 -0
- data/lib/remarkable_rails/action_controller/macro_stubs.rb +61 -21
- data/lib/remarkable_rails/action_controller/matchers/render_template_matcher.rb +9 -6
- data/lib/remarkable_rails/action_controller/matchers/respond_with_matcher.rb +21 -9
- data/spec/action_controller/macro_stubs_spec.rb +66 -11
- data/spec/action_controller/respond_with_matcher_spec.rb +3 -1
- data/spec/application/tasks_controller.rb +6 -1
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
* mock_models now creates a second class method to be used on the index action [#71]
|
2
|
+
In other words, mock_models :project will create:
|
3
|
+
|
4
|
+
def self.mock_project
|
5
|
+
proc { mock_project }
|
6
|
+
end
|
7
|
+
|
8
|
+
# This was added to be used on index actions
|
9
|
+
def self.mock_projects
|
10
|
+
proc { [ mock_project ] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def mock_project(stubs={})
|
14
|
+
@project ||= mock_model(Project, stubs)
|
15
|
+
end
|
16
|
+
|
17
|
+
* Allow multiple args to be given to :with in expects. If you need to verify that
|
18
|
+
an array is being sent, you need to send an array inside another array [#70]
|
19
|
+
|
20
|
+
* Allow procs or blocks to be given to respond_with_body and respond_with :body [#67]
|
21
|
+
|
22
|
+
* Allow ordered to be given to macro stubs as option [#66]
|
23
|
+
|
24
|
+
* Allow multiple methods to be given to expects [#65]
|
25
|
+
|
1
26
|
# v3.1
|
2
27
|
|
3
28
|
* Ensure set_cookies and set_session work with arrays [#55]
|
@@ -56,12 +56,27 @@ module Remarkable
|
|
56
56
|
# This also works in the rspec way:
|
57
57
|
#
|
58
58
|
# it { should assign_to(:project).with_stubs }
|
59
|
-
# it { should
|
59
|
+
# it { should render_template('show').with_expectations }
|
60
|
+
#
|
61
|
+
# == Attention!
|
62
|
+
#
|
63
|
+
# If you need to check that an array is being sent to a method, you need to
|
64
|
+
# give an array inside another array, for example:
|
65
|
+
#
|
66
|
+
# expects :comment_ids=, :on => Post, :with => [1,2,3]
|
67
|
+
#
|
68
|
+
# Is the same as:
|
69
|
+
#
|
70
|
+
# Post.comment_ids = (1, 2, 3)
|
71
|
+
#
|
72
|
+
# And it won't work. The right way to handle this is:
|
73
|
+
#
|
74
|
+
# expects :comment_ids=, :on => Post, :with => [[1,2,3]]
|
60
75
|
#
|
61
76
|
# == mock_models
|
62
77
|
#
|
63
78
|
# You don't have to play with proc all the time. You can call mock_models which
|
64
|
-
# creates
|
79
|
+
# creates two class methods that simply returns a proc and a instance method that
|
65
80
|
# do the actual mock.
|
66
81
|
#
|
67
82
|
# describe ProjectsController do
|
@@ -71,6 +86,11 @@ module Remarkable
|
|
71
86
|
#
|
72
87
|
# def self.mock_project
|
73
88
|
# proc { mock_project }
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# # To be used on index actions
|
92
|
+
# def self.mock_projects
|
93
|
+
# proc { [mock_project] }
|
74
94
|
# end
|
75
95
|
#
|
76
96
|
# def mock_project(stubs={})
|
@@ -180,8 +200,9 @@ module Remarkable
|
|
180
200
|
module ClassMethods
|
181
201
|
|
182
202
|
# Creates a chain that will be evaluated as stub or expectation. The
|
183
|
-
# first parameter is the method expected.
|
184
|
-
# to calculate the returned value. See
|
203
|
+
# first parameter is the method expected. You can also specify multiple
|
204
|
+
# methods to stub and give a block to calculate the returned value. See
|
205
|
+
# examples below.
|
185
206
|
#
|
186
207
|
# == Options
|
187
208
|
#
|
@@ -195,18 +216,26 @@ module Remarkable
|
|
195
216
|
# required.
|
196
217
|
#
|
197
218
|
# * <tt>:times</tt> - The number of times the object will receive the
|
198
|
-
# method. Used only in expectations and when not given, defaults to 1.
|
219
|
+
# method. Used only in expectations and when not given, defaults to 1.
|
220
|
+
#
|
221
|
+
# * <tt>:ordered</tt> - When true specifies that expectations should
|
222
|
+
# be received in order.
|
199
223
|
#
|
200
224
|
# == Example
|
201
225
|
#
|
202
226
|
# expects :new, :on => Project, :returns => :mock_project, :times => 2
|
203
227
|
#
|
228
|
+
# expects :new, :find, :on => Project, :returns => :mock_project
|
229
|
+
#
|
204
230
|
# expects :human_attribute_name, :on => Project, :with => :title do |attr|
|
205
231
|
# attr.to_s.humanize
|
206
232
|
# end
|
207
233
|
#
|
208
234
|
def expects(*args, &block)
|
209
|
-
|
235
|
+
options = args.extract_options!
|
236
|
+
args.each do |arg|
|
237
|
+
write_inheritable_array(:expects_chain, [ [ arg, options, block] ])
|
238
|
+
end
|
210
239
|
end
|
211
240
|
|
212
241
|
# The mime type of the request. The value given will be called transformed
|
@@ -396,15 +425,20 @@ module Remarkable
|
|
396
425
|
# mock_models :project
|
397
426
|
# end
|
398
427
|
#
|
399
|
-
# Will create
|
428
|
+
# Will create one instance and two class mock methods for you:
|
400
429
|
#
|
401
430
|
# def self.mock_project
|
402
431
|
# proc { mock_project }
|
432
|
+
# end
|
433
|
+
#
|
434
|
+
# # To be used on index actions
|
435
|
+
# def self.mock_projects
|
436
|
+
# proc { [ mock_project ] }
|
403
437
|
# end
|
404
438
|
#
|
405
439
|
# def mock_project(stubs={})
|
406
440
|
# @project ||= mock_model(Project, stubs)
|
407
|
-
# end
|
441
|
+
# end
|
408
442
|
#
|
409
443
|
# If you want to create just the instance method, you can give
|
410
444
|
# :class_method => false as option.
|
@@ -413,12 +447,14 @@ module Remarkable
|
|
413
447
|
options = models.extract_options!
|
414
448
|
options = { :class_method => true }.merge(options)
|
415
449
|
|
416
|
-
models.each do |model|
|
450
|
+
models.each do |model|
|
451
|
+
model = model.to_s
|
417
452
|
self.class_eval <<-METHOD
|
418
|
-
#{"def self.mock_#{model}; proc { mock_#{model} }; end"
|
453
|
+
#{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
|
454
|
+
#{"def self.mock_#{model.pluralize}; proc { [ mock_#{model} ] }; end" if options[:class_method]}
|
419
455
|
|
420
456
|
def mock_#{model}(stubs={})
|
421
|
-
@#{model} ||= mock_model(#{model.
|
457
|
+
@#{model} ||= mock_model(#{model.classify}, stubs)
|
422
458
|
end
|
423
459
|
METHOD
|
424
460
|
end
|
@@ -433,19 +469,22 @@ module Remarkable
|
|
433
469
|
def evaluate_expectation_chain(use_expectations=true) #:nodoc:
|
434
470
|
return if self.expects_chain.nil?
|
435
471
|
|
436
|
-
self.expects_chain.each do |method,
|
437
|
-
|
438
|
-
|
439
|
-
# Those are used both in expectations and stubs
|
440
|
-
object = evaluate_value(options.delete(:on))
|
441
|
-
return_value = evaluate_value(options.delete(:returns))
|
442
|
-
|
472
|
+
self.expects_chain.each do |method, options, block|
|
473
|
+
object = evaluate_value(options[:on])
|
443
474
|
raise ScriptError, "You have to give me :on as an option when calling :expects." if object.nil?
|
444
475
|
|
445
476
|
if use_expectations
|
446
|
-
chain = object.should_receive(method)
|
447
|
-
|
448
|
-
|
477
|
+
chain = object.should_receive(method)
|
478
|
+
|
479
|
+
if options.key?(:with)
|
480
|
+
with = evaluate_value(options[:with])
|
481
|
+
chain = chain.with(*with)
|
482
|
+
end
|
483
|
+
|
484
|
+
times = options[:times] || 1
|
485
|
+
chain = chain.exactly(times).times
|
486
|
+
|
487
|
+
chain = chain.ordered if options[:ordered]
|
449
488
|
else
|
450
489
|
chain = object.stub!(method)
|
451
490
|
end
|
@@ -453,6 +492,7 @@ module Remarkable
|
|
453
492
|
chain = if block
|
454
493
|
chain.and_return(&block)
|
455
494
|
else
|
495
|
+
return_value = evaluate_value(options[:returns])
|
456
496
|
chain.and_return(return_value)
|
457
497
|
end
|
458
498
|
end
|
@@ -122,23 +122,26 @@ module Remarkable
|
|
122
122
|
# Extensions check does not work in Rails 2.1.x.
|
123
123
|
#
|
124
124
|
def render_template(*args, &block)
|
125
|
-
options = args.extract_options!
|
126
|
-
|
125
|
+
options = args.extract_options!
|
126
|
+
options.merge!(:template => args.first)
|
127
|
+
RenderTemplateMatcher.new(options, &block).spec(self)
|
127
128
|
end
|
128
129
|
|
129
130
|
# This is just a shortcut for render_template :layout => layout. It's also
|
130
131
|
# used for Shoulda compatibility. Check render_template for more information.
|
131
132
|
#
|
132
133
|
def render_with_layout(*args, &block)
|
133
|
-
options = args.extract_options!
|
134
|
-
|
134
|
+
options = args.extract_options!
|
135
|
+
options.merge!(:layout => args.first)
|
136
|
+
RenderTemplateMatcher.new(options, &block).spec(self)
|
135
137
|
end
|
136
138
|
|
137
139
|
# This is just a shortcut for render_template :layout => nil. It's also
|
138
140
|
# used for Shoulda compatibility. Check render_template for more information.
|
139
141
|
#
|
140
|
-
def render_without_layout(options={}, &block)
|
141
|
-
|
142
|
+
def render_without_layout(options={}, &block)
|
143
|
+
options.merge!(:layout => nil)
|
144
|
+
RenderTemplateMatcher.new(options, &block).spec(self)
|
142
145
|
end
|
143
146
|
|
144
147
|
end
|
@@ -2,7 +2,7 @@ module Remarkable
|
|
2
2
|
module ActionController
|
3
3
|
module Matchers
|
4
4
|
class RespondWithMatcher < Remarkable::ActionController::Base #:nodoc:
|
5
|
-
arguments
|
5
|
+
arguments :block => true
|
6
6
|
|
7
7
|
optional :with, :body, :content_type
|
8
8
|
|
@@ -11,7 +11,7 @@ module Remarkable
|
|
11
11
|
@controller = @spec.instance_variable_get('@controller')
|
12
12
|
end
|
13
13
|
|
14
|
-
before_assert :evaluate_content_type
|
14
|
+
before_assert :evaluate_content_type, :evaluate_body
|
15
15
|
|
16
16
|
assertions :status_matches?, :body_matches?, :content_type_matches?
|
17
17
|
|
@@ -45,7 +45,6 @@ module Remarkable
|
|
45
45
|
assert_contains(@response.content_type, @options[:content_type])
|
46
46
|
end
|
47
47
|
|
48
|
-
# Evaluate content_type before assertions to have nice descriptions
|
49
48
|
def evaluate_content_type
|
50
49
|
return unless @options.key?(:content_type)
|
51
50
|
|
@@ -57,6 +56,14 @@ module Remarkable
|
|
57
56
|
else
|
58
57
|
@options[:content_type].to_s
|
59
58
|
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def evaluate_body
|
62
|
+
if @options.key?(:body) || @block
|
63
|
+
value = @options.key?(:body) ? @options[:body] : @block
|
64
|
+
value = @spec.instance_eval(&value) if value.is_a?(Proc)
|
65
|
+
@options[:body] = value
|
66
|
+
end
|
60
67
|
end
|
61
68
|
|
62
69
|
def interpolation_options
|
@@ -98,16 +105,20 @@ module Remarkable
|
|
98
105
|
# it { should respond_with(300..399).content_type(Mime::XML) }
|
99
106
|
#
|
100
107
|
def respond_with(*args, &block)
|
101
|
-
options = args.extract_options!
|
102
|
-
|
108
|
+
options = args.extract_options!
|
109
|
+
options.merge!(:with => args.first)
|
110
|
+
RespondWithMatcher.new(options, &block).spec(self)
|
103
111
|
end
|
104
112
|
|
105
113
|
# This is just a shortcut for respond_with :body => body. Check respond_with
|
106
114
|
# for more information.
|
107
115
|
#
|
108
116
|
def respond_with_body(*args, &block)
|
109
|
-
options = args.extract_options!
|
110
|
-
|
117
|
+
options = args.extract_options!
|
118
|
+
# Since body can be also given as block, only merge if any arguments was
|
119
|
+
# actually sent.
|
120
|
+
options.merge!(:body => args.first) unless args.empty?
|
121
|
+
RespondWithMatcher.new(options, &block).spec(self)
|
111
122
|
end
|
112
123
|
|
113
124
|
# This is just a shortcut for respond_with :content_type => content_type.
|
@@ -115,8 +126,9 @@ module Remarkable
|
|
115
126
|
# information.
|
116
127
|
#
|
117
128
|
def respond_with_content_type(*args, &block)
|
118
|
-
options = args.extract_options!
|
119
|
-
|
129
|
+
options = args.extract_options!
|
130
|
+
options.merge!(:content_type => args.first)
|
131
|
+
RespondWithMatcher.new(options, &block).spec(self)
|
120
132
|
end
|
121
133
|
|
122
134
|
end
|
@@ -10,15 +10,22 @@ describe 'MacroStubs' do
|
|
10
10
|
def current_id; '37'; end
|
11
11
|
|
12
12
|
describe 'mock_models' do
|
13
|
-
before(:each) do
|
14
|
-
self.class.metaclass.send(:undef_method, :
|
15
|
-
self.class.send(:undef_method, :mock_project)
|
13
|
+
before(:each) do
|
14
|
+
self.class.metaclass.send(:undef_method, :mock_projects) if self.class.respond_to?(:mock_projects)
|
15
|
+
self.class.metaclass.send(:undef_method, :mock_project) if self.class.respond_to?(:mock_project)
|
16
|
+
self.class.send(:undef_method, :mock_project) if self.respond_to?(:mock_project)
|
16
17
|
end
|
17
18
|
|
18
|
-
it 'should create a class mock method' do
|
19
|
+
it 'should create a class singular mock method' do
|
19
20
|
self.class.respond_to?(:mock_project).should be_false
|
20
21
|
self.class.mock_models :project
|
21
22
|
self.class.respond_to?(:mock_project).should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should create a class plural mock method' do
|
26
|
+
self.class.respond_to?(:mock_projects).should be_false
|
27
|
+
self.class.mock_models :project
|
28
|
+
self.class.respond_to?(:mock_projects).should be_true
|
22
29
|
end
|
23
30
|
|
24
31
|
it 'should create an instance mock method' do
|
@@ -35,18 +42,66 @@ describe 'MacroStubs' do
|
|
35
42
|
self.respond_to?(:mock_project).should be_true
|
36
43
|
end
|
37
44
|
|
38
|
-
it 'should create procs which evals to
|
45
|
+
it 'should create procs which evals to a mock dynamically' do
|
39
46
|
proc = self.class.mock_task
|
40
47
|
proc.should be_kind_of(Proc)
|
41
48
|
|
42
|
-
|
43
|
-
instance_eval(&proc)
|
44
|
-
|
49
|
+
@task.should be_nil
|
50
|
+
instance_eval(&proc).should == mock_task
|
51
|
+
@task.should_not be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should create procs which evals to an array of mocks dynamically' do
|
55
|
+
proc = self.class.mock_tasks
|
56
|
+
proc.should be_kind_of(Proc)
|
57
|
+
|
58
|
+
@task.should be_nil
|
59
|
+
instance_eval(&proc).should == [ mock_task ]
|
60
|
+
@task.should == mock_task
|
45
61
|
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'failures' do
|
65
|
+
expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
|
66
|
+
expects :max, :min, :count, :on => Task, :ordered => true
|
67
|
+
|
68
|
+
get :show, :id => 37
|
69
|
+
|
70
|
+
it 'should fail if expectation is not met' do
|
71
|
+
self.stub!(:current_id).and_return("42")
|
72
|
+
|
73
|
+
lambda {
|
74
|
+
run_action!(true)
|
75
|
+
}.should raise_error(Spec::Mocks::MockExpectationError, /expected :find with \("42"\) but received it with \("37"\)/)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should fail if expectations are received out of order' do
|
79
|
+
lambda {
|
80
|
+
run_action!(true)
|
81
|
+
}.should raise_error(Spec::Mocks::MockExpectationError, /received :count out of order/)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should splat an array given to with' do
|
85
|
+
self.stub!(:current_id).and_return([1, 2, 3])
|
86
|
+
run_expectations!
|
87
|
+
|
88
|
+
lambda {
|
89
|
+
Task.find([1,2,3])
|
90
|
+
}.should raise_error(Spec::Mocks::MockExpectationError, /expected :find with \(1\, 2\, 3\) but received it with \(\[1\, 2\, 3\]\)/)
|
91
|
+
|
92
|
+
lambda {
|
93
|
+
Task.find(1, 2, 3)
|
94
|
+
}.should_not raise_error
|
95
|
+
end
|
96
|
+
|
97
|
+
after(:each) do
|
98
|
+
teardown_mocks_for_rspec
|
99
|
+
end
|
46
100
|
end
|
47
101
|
|
48
102
|
describe 'when extending describe group behavior' do
|
49
|
-
expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
|
103
|
+
expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
|
104
|
+
expects :count, :max, :min, :on => Task
|
50
105
|
|
51
106
|
get :show, :id => 37
|
52
107
|
params :special_task_id => 42
|
@@ -89,8 +144,8 @@ describe 'MacroStubs' do
|
|
89
144
|
it 'should run expectations without performing an action' do
|
90
145
|
self.should_receive(:current_id).once.and_return('37')
|
91
146
|
run_expectations!
|
92
|
-
@controller.send(:performed?).should_not be_true
|
93
|
-
|
147
|
+
@controller.send(:performed?).should_not be_true
|
148
|
+
get :show, :id => '37' # Execute the action to match expectations
|
94
149
|
end
|
95
150
|
|
96
151
|
it 'should run action with stubs' do
|
@@ -77,7 +77,9 @@ describe 'respond_with' do
|
|
77
77
|
before(:each) { build_response { respond_to{ |format| format.xml { render :xml => [].to_xml } } } }
|
78
78
|
|
79
79
|
it { should respond_with_body(%{<?xml version="1.0" encoding="UTF-8"?>\n<nil-classes type="array"/>\n}) }
|
80
|
-
it { should respond_with_body(/xml/) }
|
80
|
+
it { should respond_with_body(/xml/) }
|
81
|
+
it { should respond_with_body{/xml/} }
|
82
|
+
it { should respond_with_body proc{/xml/} }
|
81
83
|
it { should_not respond_with_body('html') }
|
82
84
|
it { should_not respond_with_body(/html/) }
|
83
85
|
end
|
@@ -11,7 +11,12 @@ class TasksController < ApplicationController
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def show
|
14
|
-
@task = Task.find(params[:id])
|
14
|
+
@task = Task.find(params[:id])
|
15
|
+
|
16
|
+
# Multiple expects
|
17
|
+
Task.count
|
18
|
+
Task.max
|
19
|
+
Task.min
|
15
20
|
|
16
21
|
respond_to do |format|
|
17
22
|
format.html { render :text => 'show' }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remarkable_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Brando
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-05-
|
13
|
+
date: 2009-05-13 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 3.1.
|
34
|
+
version: 3.1.1
|
35
35
|
version:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: remarkable_activerecord
|
@@ -41,7 +41,7 @@ dependencies:
|
|
41
41
|
requirements:
|
42
42
|
- - ">="
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
version: 3.1.
|
44
|
+
version: 3.1.1
|
45
45
|
version:
|
46
46
|
description: "Remarkable Rails: collection of matchers and macros with I18n for Rails"
|
47
47
|
email:
|