acts-as-approvable 0.6.7 → 0.6.8.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/.gitignore +2 -5
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Appraisals +14 -10
- data/CHANGELOG +16 -0
- data/Gemfile.lock +60 -20
- data/README.md +1 -2
- data/Rakefile +44 -16
- data/VERSION +1 -1
- data/acts-as-approvable.gemspec +21 -11
- data/features/create_approval.feature +26 -0
- data/features/step_definitions/cucumber_steps.rb +86 -0
- data/features/support/env.rb +14 -0
- data/features/support/large.txt +29943 -0
- data/features/support/second_large.txt +31798 -0
- data/features/update_approval.feature +34 -0
- data/gemfiles/Gemfile.ci +14 -0
- data/gemfiles/Gemfile.ci.lock +98 -0
- data/gemfiles/mysql2.gemfile +7 -0
- data/gemfiles/mysql2.gemfile.lock +92 -0
- data/gemfiles/rails2.gemfile +1 -0
- data/gemfiles/rails2.gemfile.lock +59 -17
- data/gemfiles/rails30.gemfile +1 -0
- data/gemfiles/rails30.gemfile.lock +54 -14
- data/gemfiles/rails31.gemfile +1 -0
- data/gemfiles/rails31.gemfile.lock +54 -14
- data/gemfiles/sqlite.gemfile +7 -0
- data/generators/acts_as_approvable/templates/create_approvals.rb +8 -7
- data/lib/acts-as-approvable.rb +2 -3
- data/lib/acts_as_approvable/approval.rb +3 -2
- data/lib/acts_as_approvable/model.rb +55 -0
- data/lib/acts_as_approvable/model/class_methods.rb +63 -0
- data/lib/acts_as_approvable/model/create_instance_methods.rb +83 -0
- data/lib/acts_as_approvable/model/instance_methods.rb +89 -0
- data/lib/acts_as_approvable/model/update_instance_methods.rb +61 -0
- data/lib/acts_as_approvable/railtie.rb +1 -1
- data/lib/generators/acts_as_approvable/templates/create_approvals.rb +8 -7
- data/spec/acts_as_approvable/approval_spec.rb +475 -0
- data/spec/acts_as_approvable/model/class_methods_spec.rb +219 -0
- data/spec/acts_as_approvable/model/create_instance_methods_spec.rb +149 -0
- data/spec/acts_as_approvable/model/instance_methods_spec.rb +328 -0
- data/spec/acts_as_approvable/model/update_instance_methods_spec.rb +111 -0
- data/spec/acts_as_approvable/model_spec.rb +90 -0
- data/spec/acts_as_approvable/ownership/class_methods_spec.rb +101 -0
- data/spec/acts_as_approvable/ownership/instance_methods_spec.rb +32 -0
- data/spec/acts_as_approvable/ownership_spec.rb +51 -0
- data/spec/acts_as_approvable_spec.rb +29 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/database.rb +46 -0
- data/spec/support/database.yml +12 -0
- data/spec/support/matchers.rb +87 -0
- data/spec/support/models.rb +60 -0
- data/{test → spec/support}/schema.rb +15 -9
- metadata +156 -53
- data/gemfiles/rails32.gemfile +0 -8
- data/gemfiles/rails32.gemfile.lock +0 -99
- data/lib/acts_as_approvable/acts_as_approvable.rb +0 -291
- data/test/acts_as_approvable_model_test.rb +0 -459
- data/test/acts_as_approvable_ownership_test.rb +0 -132
- data/test/acts_as_approvable_schema_test.rb +0 -13
- data/test/acts_as_approvable_test.rb +0 -8
- data/test/database.yml +0 -7
- data/test/support.rb +0 -19
- data/test/test_helper.rb +0 -62
@@ -0,0 +1,61 @@
|
|
1
|
+
module ActsAsApprovable
|
2
|
+
module Model
|
3
|
+
##
|
4
|
+
# Instance methods that apply to the :update event specifically.
|
5
|
+
module UpdateInstanceMethods
|
6
|
+
##
|
7
|
+
# Retrieve all approval records for `:update` events.
|
8
|
+
def update_approvals(all = true)
|
9
|
+
all ? approvals.find_all_by_event('update') : approvals.find_all_by_event_and_state('update', 0)
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Returns true if the record has any `#update_approvals` that are pending
|
14
|
+
# approval.
|
15
|
+
def pending_changes?
|
16
|
+
!update_approvals(false).empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Returns true if any notable (eg. not ignored) fields have been changed.
|
21
|
+
def changed_notably?
|
22
|
+
notably_changed.any?
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Returns an array of any notable (eg. not ignored) fields that have not
|
27
|
+
# been changed.
|
28
|
+
#
|
29
|
+
# @return [Array] a list of changed fields.
|
30
|
+
def notably_changed
|
31
|
+
approvable_fields.select { |field| changed.include?(field) }
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Returns a list of fields that require approval.
|
36
|
+
def approvable_fields
|
37
|
+
self.class.approvable_fields
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def approvable_update?
|
42
|
+
approvals_enabled? and approvable_on?(:update) and changed_notably?
|
43
|
+
end
|
44
|
+
|
45
|
+
def approvable_update
|
46
|
+
changed = {}
|
47
|
+
originals = {}
|
48
|
+
|
49
|
+
notably_changed.each do |attr|
|
50
|
+
original, changed_to = changes[attr]
|
51
|
+
|
52
|
+
write_attribute(attr.to_s, original)
|
53
|
+
changed[attr] = changed_to
|
54
|
+
originals[attr] = original
|
55
|
+
end
|
56
|
+
|
57
|
+
@approval = approvals.build(:event => 'update', :state => 'pending', :object => changed, :original => originals)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActsAsApprovable
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
initializer 'acts_as_approvable.configure_rails_initialization' do |app|
|
4
|
-
ActiveRecord::Base.send :
|
4
|
+
ActiveRecord::Base.send :extend, ActsAsApprovable::Model
|
5
5
|
end
|
6
6
|
end
|
7
7
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
class CreateApprovals < ActiveRecord::Migration
|
2
2
|
def self.up
|
3
3
|
create_table :approvals do |t|
|
4
|
-
t.string
|
5
|
-
t.integer
|
6
|
-
t.string
|
7
|
-
t.integer
|
8
|
-
<% if options[:owner] %> t.integer
|
9
|
-
<% end %> t.text
|
10
|
-
t.text
|
4
|
+
t.string :item_type, :null => false
|
5
|
+
t.integer :item_id, :null => false
|
6
|
+
t.string :event, :null => false
|
7
|
+
t.integer :state, :null => false, :default => 0
|
8
|
+
<% if options[:owner] %> t.integer :owner_id
|
9
|
+
<% end %> t.text :object, :limit => 16777216
|
10
|
+
t.text :original, :limit => 16777216
|
11
|
+
t.text :reason
|
11
12
|
|
12
13
|
t.timestamps
|
13
14
|
end
|
@@ -0,0 +1,475 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Approval do
|
4
|
+
before(:each) do
|
5
|
+
subject.stub(:save! => true, :save => true)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should serialize :object' do
|
9
|
+
described_class.serialized_attributes.keys.should include('object')
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.associations' do
|
13
|
+
it { should belong_to(:item) }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.validates' do
|
17
|
+
it { should validate_presence_of(:item) }
|
18
|
+
it { should validate_inclusion_of(:event).in(%w(create update)) }
|
19
|
+
it { should validate_numericality_of(:state) }
|
20
|
+
it { should ensure_inclusion_of(:state).in_range(0..(described_class::STATES.length - 1)).with_low_message(/greater than/).with_high_message(/less than/)}
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.enumerate_state' do
|
24
|
+
it 'enumerates "pending" to 0' do
|
25
|
+
described_class.enumerate_state('pending').should be(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'enumerates "approved" to 1' do
|
29
|
+
described_class.enumerate_state('approved').should be(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'enumerates "rejected" to 2' do
|
33
|
+
described_class.enumerate_state('rejected').should be(2)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'enumerates other values to nil' do
|
37
|
+
described_class.enumerate_state('not_a_state').should_not be
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '.enumerate_states' do
|
42
|
+
it 'enumerates many states at once' do
|
43
|
+
described_class.enumerate_states('pending', 'approved', 'rejected').should == [0, 1, 2]
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'ignores states it does not know' do
|
47
|
+
described_class.enumerate_states('pending', 'not_a_state', 'rejected').should == [0, 2]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '.options_for_state' do
|
52
|
+
it 'returns an array usable by #options_for_select' do
|
53
|
+
described_class.options_for_state.should be_an_options_array
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'includes an "all" option' do
|
57
|
+
described_class.options_for_state.should include(['All', -1])
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'includes the pending state' do
|
61
|
+
described_class.options_for_state.should include(['Pending', 0])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'includes the approved state' do
|
65
|
+
described_class.options_for_state.should include(['Approved', 1])
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'includes the rejected state' do
|
69
|
+
described_class.options_for_state.should include(['Rejected', 2])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '.options_for_type' do
|
74
|
+
before(:each) do
|
75
|
+
@default = DefaultApprovable.create
|
76
|
+
@creates = CreatesApprovable.create
|
77
|
+
@updates = UpdatesApprovable.create
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns an array usable by #options_for_select' do
|
81
|
+
described_class.options_for_type.should be_an_options_array
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'includes all types with approvals' do
|
85
|
+
described_class.options_for_type.should include('DefaultApprovable')
|
86
|
+
described_class.options_for_type.should include('CreatesApprovable')
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'does not include types without approvals' do
|
90
|
+
described_class.options_for_type.should_not include('UpdatesApprovable')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'includes a prompt if requested' do
|
94
|
+
described_class.options_for_type(true).should include(['All Types', nil])
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'does not includes a prompt by default' do
|
98
|
+
described_class.options_for_type.should_not include(['All Types', nil])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#state' do
|
103
|
+
it 'returns the state as a string' do
|
104
|
+
subject.state.should be_a(String)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'attempts to read the state attribute' do
|
108
|
+
subject.should_receive(:read_attribute).with(:state)
|
109
|
+
subject.state
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#state_was' do
|
114
|
+
it 'returns the state as a string' do
|
115
|
+
subject.state_was.should be_a(String)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'attempts to read the changed state attribute' do
|
119
|
+
subject.should_receive(:changed_attributes).and_return({:state => 1})
|
120
|
+
subject.state_was.should == 'approved'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#state=' do
|
125
|
+
it 'writes the attribute value' do
|
126
|
+
subject.should_receive(:write_attribute)
|
127
|
+
subject.send(:state=, 'pending')
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'enumerates the given state' do
|
131
|
+
subject.should_receive(:write_attribute).with(:state, 0)
|
132
|
+
subject.send(:state=, 'pending')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'skips enumeration for numeric values' do
|
136
|
+
subject.should_receive(:write_attribute).with(:state, 10)
|
137
|
+
subject.send(:state=, 10)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when the state is pending' do
|
142
|
+
before(:each) do
|
143
|
+
subject.stub(:state => 'pending')
|
144
|
+
end
|
145
|
+
|
146
|
+
it { should be_pending }
|
147
|
+
it { should_not be_approved }
|
148
|
+
it { should_not be_rejected }
|
149
|
+
it { should_not be_locked }
|
150
|
+
it { should be_unlocked }
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when the state is approved' do
|
154
|
+
before(:each) do
|
155
|
+
subject.stub(:state => 'approved')
|
156
|
+
end
|
157
|
+
|
158
|
+
it { should_not be_pending }
|
159
|
+
it { should be_approved }
|
160
|
+
it { should_not be_rejected }
|
161
|
+
it { should be_locked }
|
162
|
+
it { should_not be_unlocked }
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'when the state is rejected' do
|
166
|
+
before(:each) do
|
167
|
+
subject.stub(:state => 'rejected')
|
168
|
+
end
|
169
|
+
|
170
|
+
it { should_not be_pending }
|
171
|
+
it { should_not be_approved }
|
172
|
+
it { should be_rejected }
|
173
|
+
it { should be_locked }
|
174
|
+
it { should_not be_unlocked }
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'when the event is :update' do
|
178
|
+
before(:each) do
|
179
|
+
subject.stub(:event => 'update')
|
180
|
+
end
|
181
|
+
|
182
|
+
it { should be_update }
|
183
|
+
it { should_not be_create }
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'when the event is :create' do
|
187
|
+
before(:each) do
|
188
|
+
subject.stub(:event => 'create')
|
189
|
+
end
|
190
|
+
|
191
|
+
it { should_not be_update }
|
192
|
+
it { should be_create }
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'when the approval is unlocked' do
|
196
|
+
before(:each) do
|
197
|
+
@item = DefaultApprovable.without_approval { |m| m.create }
|
198
|
+
subject.stub(:locked? => false, :created_at => Time.now, :item => @item)
|
199
|
+
@item.stub(:updated_at => Time.now)
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#able_to_save?' do
|
203
|
+
it { should be_able_to_save }
|
204
|
+
|
205
|
+
it 'does not check the what the state was' do
|
206
|
+
subject.should_not_receive(:state_was)
|
207
|
+
subject.able_to_save?
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#stale?' do
|
212
|
+
it 'checks when the item was changed' do
|
213
|
+
@item.should_receive(:has_attribute?).with(:updated_at).and_return(true)
|
214
|
+
subject.stale?
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#fresh?' do
|
219
|
+
it 'checks when the item was changed' do
|
220
|
+
@item.should_receive(:has_attribute?).with(:updated_at).and_return(true)
|
221
|
+
subject.fresh?
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context 'when the approval is newer than the last update' do
|
226
|
+
before(:each) do
|
227
|
+
subject.stub(:created_at => @item.updated_at + 60)
|
228
|
+
end
|
229
|
+
|
230
|
+
it { should_not be_stale }
|
231
|
+
it { should be_fresh }
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'when the approval is older than the last update' do
|
235
|
+
before(:each) do
|
236
|
+
subject.stub(:created_at => @item.updated_at - 60)
|
237
|
+
end
|
238
|
+
|
239
|
+
it { should be_stale }
|
240
|
+
it { should_not be_fresh }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'when the approval is locked' do
|
245
|
+
before(:each) do
|
246
|
+
subject.stub(:locked? => true)
|
247
|
+
end
|
248
|
+
|
249
|
+
it { should_not be_stale }
|
250
|
+
it { should be_fresh }
|
251
|
+
|
252
|
+
describe '#able_to_save?' do
|
253
|
+
it 'checks the what the state was' do
|
254
|
+
subject.should_receive(:state_was)
|
255
|
+
subject.able_to_save?
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe '#stale?' do
|
260
|
+
it 'does not check when the item was changed' do
|
261
|
+
subject.should_not_receive(:item)
|
262
|
+
subject.stale?
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe '#fresh?' do
|
267
|
+
it 'does not check when the item was changed' do
|
268
|
+
subject.should_not_receive(:item)
|
269
|
+
subject.fresh?
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe '#approve!' do
|
274
|
+
it 'raises a Locked exception' do
|
275
|
+
expect { subject.approve! }.to raise_error(ActsAsApprovable::Error::Locked)
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'leaves the approval in a pending state' do
|
279
|
+
begin; subject.approve!; rescue ActsAsApprovable::Error::Locked; end
|
280
|
+
subject.should be_pending
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe '#reject!' do
|
285
|
+
it 'raises a Locked exception' do
|
286
|
+
expect { subject.reject! }.to raise_error(ActsAsApprovable::Error::Locked)
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'leaves the approval in a pending state' do
|
290
|
+
begin; subject.reject!; rescue ActsAsApprovable::Error::Locked; end
|
291
|
+
subject.should be_pending
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
context 'and the state is pending' do
|
296
|
+
before(:each) do
|
297
|
+
subject.stub(:state_was => 'pending')
|
298
|
+
end
|
299
|
+
|
300
|
+
it { should be_able_to_save }
|
301
|
+
end
|
302
|
+
|
303
|
+
context 'and the state is approved' do
|
304
|
+
before(:each) do
|
305
|
+
subject.stub(:state_was => 'approved')
|
306
|
+
end
|
307
|
+
|
308
|
+
it { should_not be_able_to_save }
|
309
|
+
end
|
310
|
+
|
311
|
+
context 'and the state is rejected' do
|
312
|
+
before(:each) do
|
313
|
+
subject.stub(:state_was => 'rejected')
|
314
|
+
end
|
315
|
+
|
316
|
+
it { should_not be_able_to_save }
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
context 'when the approval is stale' do
|
321
|
+
before(:each) do
|
322
|
+
@item = DefaultApprovable.without_approval { |m| m.create }
|
323
|
+
subject.stub(:stale? => true, :item => @item)
|
324
|
+
end
|
325
|
+
|
326
|
+
it { should be_stale }
|
327
|
+
it { should_not be_fresh }
|
328
|
+
|
329
|
+
describe '#approve!' do
|
330
|
+
it 'raises a Stale exception' do
|
331
|
+
expect { subject.approve! }.to raise_error(ActsAsApprovable::Error::Stale)
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'leaves the approval in a pending state' do
|
335
|
+
begin; subject.approve!; rescue ActsAsApprovable::Error::Stale; end
|
336
|
+
subject.should be_pending
|
337
|
+
end
|
338
|
+
|
339
|
+
context 'when approval is forced' do
|
340
|
+
it 'does not raise a Stale exception' do
|
341
|
+
expect { subject.approve!(true) }.to_not raise_error(ActsAsApprovable::Error::Stale)
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'leaves the approval in a pending state' do
|
345
|
+
subject.approve!(true)
|
346
|
+
subject.should be_approved
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe '#reject!' do
|
352
|
+
it 'does not raise a Stale exception' do
|
353
|
+
expect { subject.reject! }.to_not raise_error(ActsAsApprovable::Error::Stale)
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'moves the approval to a rejected state' do
|
357
|
+
subject.reject!
|
358
|
+
subject.should be_rejected
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
context 'when the approval is unlocked and fresh' do
|
364
|
+
before(:each) do
|
365
|
+
@item = DefaultApprovable.without_approval { |m| m.create }
|
366
|
+
subject.stub(:locked? => false, :stale? => false, :item => @item, :object => {})
|
367
|
+
end
|
368
|
+
|
369
|
+
it { should_not be_stale }
|
370
|
+
it { should be_fresh }
|
371
|
+
|
372
|
+
describe '#approve!' do
|
373
|
+
it 'does not raise an exception' do
|
374
|
+
expect { subject.approve! }.to_not raise_error
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'moves the approval to an approved state' do
|
378
|
+
subject.approve!
|
379
|
+
subject.should be_approved
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'calls the before and after callbacks' do
|
383
|
+
subject.should_receive(:run_item_callback).with(:before_approve).once.and_return(true)
|
384
|
+
subject.should_receive(:run_item_callback).with(:after_approve).once
|
385
|
+
subject.approve!
|
386
|
+
end
|
387
|
+
|
388
|
+
context 'when the event is :update' do
|
389
|
+
before(:each) do
|
390
|
+
subject.stub(:event => 'update')
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'sets the item attributes' do
|
394
|
+
@item.should_receive(:attributes=)
|
395
|
+
subject.approve!
|
396
|
+
end
|
397
|
+
|
398
|
+
it 'does not set the local item state' do
|
399
|
+
@item.should_not_receive(:set_approval_state)
|
400
|
+
subject.approve!
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
context 'when the event is :create' do
|
405
|
+
before(:each) do
|
406
|
+
subject.stub(:event => 'create')
|
407
|
+
end
|
408
|
+
|
409
|
+
it 'does not set the item attributes' do
|
410
|
+
@item.should_not_receive(:attributes=)
|
411
|
+
subject.approve!
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'sets the local item state' do
|
415
|
+
@item.should_receive(:set_approval_state).with('approved')
|
416
|
+
subject.approve!
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
describe '#reject!' do
|
422
|
+
it 'does not raise an exception' do
|
423
|
+
expect { subject.reject! }.to_not raise_error
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'moves the approval to a rejected state' do
|
427
|
+
subject.reject!
|
428
|
+
subject.should be_rejected
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'sets the reason if given' do
|
432
|
+
subject.reject!('reason')
|
433
|
+
subject.reason.should == 'reason'
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'calls the before and after callbacks' do
|
437
|
+
subject.should_receive(:run_item_callback).with(:before_reject).once.and_return(true)
|
438
|
+
subject.should_receive(:run_item_callback).with(:after_reject).once
|
439
|
+
subject.reject!
|
440
|
+
end
|
441
|
+
|
442
|
+
context 'when the event is :update' do
|
443
|
+
before(:each) do
|
444
|
+
subject.stub(:event => 'update')
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'does not set the item attributes' do
|
448
|
+
@item.should_not_receive(:attributes=)
|
449
|
+
subject.reject!
|
450
|
+
end
|
451
|
+
|
452
|
+
it 'does not set the local item state' do
|
453
|
+
@item.should_not_receive(:set_approval_state)
|
454
|
+
subject.reject!
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
context 'when the event is :create' do
|
459
|
+
before(:each) do
|
460
|
+
subject.stub(:event => 'create')
|
461
|
+
end
|
462
|
+
|
463
|
+
it 'does not set the item attributes' do
|
464
|
+
@item.should_not_receive(:attributes=)
|
465
|
+
subject.reject!
|
466
|
+
end
|
467
|
+
|
468
|
+
it 'sets the local item state' do
|
469
|
+
@item.should_receive(:set_approval_state).with('rejected')
|
470
|
+
subject.reject!
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|