statesman 10.0.0 → 10.2.3
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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +106 -0
- data/.rubocop.yml +5 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +25 -0
- data/Gemfile +1 -0
- data/README.md +24 -0
- data/lib/generators/statesman/active_record_transition_generator.rb +1 -1
- data/lib/generators/statesman/generator_helpers.rb +1 -1
- data/lib/statesman/adapters/active_record.rb +32 -16
- data/lib/statesman/adapters/active_record_queries.rb +13 -5
- data/lib/statesman/adapters/memory.rb +1 -1
- data/lib/statesman/adapters/type_safe_active_record_queries.rb +21 -0
- data/lib/statesman/exceptions.rb +9 -7
- data/lib/statesman/guard.rb +1 -1
- data/lib/statesman/version.rb +1 -1
- data/lib/statesman.rb +2 -0
- data/lib/tasks/statesman.rake +3 -3
- data/spec/spec_helper.rb +11 -0
- data/spec/statesman/adapters/active_record_queries_spec.rb +5 -5
- data/spec/statesman/adapters/active_record_spec.rb +87 -19
- data/spec/statesman/adapters/shared_examples.rb +2 -2
- data/spec/statesman/adapters/type_safe_active_record_queries_spec.rb +208 -0
- data/spec/statesman/exceptions_spec.rb +7 -1
- data/spec/statesman/machine_spec.rb +16 -16
- data/spec/support/active_record.rb +105 -20
- data/statesman.gemspec +6 -7
- metadata +22 -53
- data/.circleci/config.yml +0 -127
@@ -12,6 +12,9 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
12
12
|
|
13
13
|
MyActiveRecordModelTransition.serialize(:metadata, JSON)
|
14
14
|
|
15
|
+
prepare_sti_model_table
|
16
|
+
prepare_sti_transitions_table
|
17
|
+
|
15
18
|
Statesman.configure do
|
16
19
|
# Rubocop requires described_class to be used, but this block
|
17
20
|
# is instance_eval'd and described_class won't be defined
|
@@ -35,8 +38,8 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
35
38
|
allow(metadata_column).to receive_messages(sql_type: "")
|
36
39
|
allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
|
37
40
|
{ "metadata" => metadata_column })
|
38
|
-
if
|
39
|
-
|
41
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
42
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.2.0.a")
|
40
43
|
expect(MyActiveRecordModelTransition).
|
41
44
|
to receive(:type_for_attribute).with("metadata").
|
42
45
|
and_return(ActiveRecord::Type::Value.new)
|
@@ -60,10 +63,10 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
60
63
|
allow(metadata_column).to receive_messages(sql_type: "json")
|
61
64
|
allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
|
62
65
|
{ "metadata" => metadata_column })
|
63
|
-
if
|
64
|
-
|
65
|
-
serialized_type =
|
66
|
-
"",
|
66
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
67
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.2.0.a")
|
68
|
+
serialized_type = ActiveRecord::Type::Serialized.new(
|
69
|
+
"", ActiveRecord::Coders::JSON
|
67
70
|
)
|
68
71
|
expect(MyActiveRecordModelTransition).
|
69
72
|
to receive(:type_for_attribute).with("metadata").
|
@@ -88,10 +91,10 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
88
91
|
allow(metadata_column).to receive_messages(sql_type: "jsonb")
|
89
92
|
allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
|
90
93
|
{ "metadata" => metadata_column })
|
91
|
-
if
|
92
|
-
|
93
|
-
serialized_type =
|
94
|
-
"",
|
94
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
95
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.2.0.a")
|
96
|
+
serialized_type = ActiveRecord::Type::Serialized.new(
|
97
|
+
"", ActiveRecord::Coders::JSON
|
95
98
|
)
|
96
99
|
expect(MyActiveRecordModelTransition).
|
97
100
|
to receive(:type_for_attribute).with("metadata").
|
@@ -112,7 +115,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
112
115
|
end
|
113
116
|
|
114
117
|
describe "#create" do
|
115
|
-
subject {
|
118
|
+
subject(:transition) { create }
|
116
119
|
|
117
120
|
let!(:adapter) do
|
118
121
|
described_class.new(MyActiveRecordModelTransition, model, observer)
|
@@ -165,27 +168,25 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
165
168
|
|
166
169
|
context "ActiveRecord::RecordNotUnique unrelated to this transition" do
|
167
170
|
let(:error) do
|
168
|
-
if
|
169
|
-
|
171
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
172
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.0.0")
|
170
173
|
ActiveRecord::RecordNotUnique.new("unrelated")
|
171
174
|
else
|
172
175
|
ActiveRecord::RecordNotUnique.new("unrelated", nil)
|
173
176
|
end
|
174
177
|
end
|
175
178
|
|
176
|
-
it {
|
179
|
+
it { expect { transition }.to raise_exception(ActiveRecord::RecordNotUnique) }
|
177
180
|
end
|
178
181
|
|
179
182
|
context "other errors" do
|
180
183
|
let(:error) { StandardError }
|
181
184
|
|
182
|
-
it {
|
185
|
+
it { expect { transition }.to raise_exception(StandardError) }
|
183
186
|
end
|
184
187
|
end
|
185
188
|
|
186
189
|
describe "updating the most_recent column" do
|
187
|
-
subject { create }
|
188
|
-
|
189
190
|
context "with no previous transition" do
|
190
191
|
its(:most_recent) { is_expected.to eq(true) }
|
191
192
|
end
|
@@ -302,6 +303,57 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
302
303
|
from(true).to be_falsey
|
303
304
|
end
|
304
305
|
end
|
306
|
+
|
307
|
+
context "when transition uses STI" do
|
308
|
+
let(:sti_model) { StiActiveRecordModel.create }
|
309
|
+
|
310
|
+
let(:adapter_a) do
|
311
|
+
described_class.new(
|
312
|
+
StiAActiveRecordModelTransition,
|
313
|
+
sti_model,
|
314
|
+
observer,
|
315
|
+
{ association_name: :sti_a_active_record_model_transitions },
|
316
|
+
)
|
317
|
+
end
|
318
|
+
let(:adapter_b) do
|
319
|
+
described_class.new(
|
320
|
+
StiBActiveRecordModelTransition,
|
321
|
+
sti_model,
|
322
|
+
observer,
|
323
|
+
{ association_name: :sti_b_active_record_model_transitions },
|
324
|
+
)
|
325
|
+
end
|
326
|
+
let(:create) { adapter_a.create(from, to) }
|
327
|
+
|
328
|
+
context "with a previous unrelated transition" do
|
329
|
+
let!(:transition_b) { adapter_b.create(from, to) }
|
330
|
+
|
331
|
+
its(:most_recent) { is_expected.to eq(true) }
|
332
|
+
|
333
|
+
it "doesn't update the previous transition's most_recent flag" do
|
334
|
+
expect { create }.
|
335
|
+
to_not(change { transition_b.reload.most_recent })
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
context "with previous related and unrelated transitions" do
|
340
|
+
let!(:transition_a) { adapter_a.create(from, to) }
|
341
|
+
let!(:transition_b) { adapter_b.create(from, to) }
|
342
|
+
|
343
|
+
its(:most_recent) { is_expected.to eq(true) }
|
344
|
+
|
345
|
+
it "updates the previous transition's most_recent flag" do
|
346
|
+
expect { create }.
|
347
|
+
to change { transition_a.reload.most_recent }.
|
348
|
+
from(true).to be_falsey
|
349
|
+
end
|
350
|
+
|
351
|
+
it "doesn't update the previous unrelated transition's most_recent flag" do
|
352
|
+
expect { create }.
|
353
|
+
to_not(change { transition_b.reload.most_recent })
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
305
357
|
end
|
306
358
|
end
|
307
359
|
|
@@ -310,9 +362,9 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
310
362
|
described_class.new(MyActiveRecordModelTransition, model, observer)
|
311
363
|
end
|
312
364
|
|
313
|
-
before { adapter.create(:x, :y) }
|
314
|
-
|
315
365
|
context "with a previously looked up transition" do
|
366
|
+
before { adapter.create(:x, :y) }
|
367
|
+
|
316
368
|
before { adapter.last }
|
317
369
|
|
318
370
|
it "caches the transition" do
|
@@ -378,6 +430,22 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
378
430
|
expect(adapter.last.to_state).to eq("y")
|
379
431
|
end
|
380
432
|
end
|
433
|
+
|
434
|
+
context "without previous transitions" do
|
435
|
+
it "does query the database only once" do
|
436
|
+
expect(model.my_active_record_model_transitions).
|
437
|
+
to receive(:order).once.and_call_original
|
438
|
+
|
439
|
+
expect(adapter.last).to eq(nil)
|
440
|
+
expect(adapter.last).to eq(nil)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
describe "#reset" do
|
446
|
+
it "works with empty cache" do
|
447
|
+
expect { model.state_machine.reset }.to_not raise_error
|
448
|
+
end
|
381
449
|
end
|
382
450
|
|
383
451
|
it "resets last with #reload" do
|
@@ -30,14 +30,14 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
|
|
30
30
|
end
|
31
31
|
|
32
32
|
describe "#create" do
|
33
|
-
subject {
|
33
|
+
subject(:transition) { create }
|
34
34
|
|
35
35
|
let(:from) { :x }
|
36
36
|
let(:to) { :y }
|
37
37
|
let(:there) { :z }
|
38
38
|
let(:create) { adapter.create(from, to) }
|
39
39
|
|
40
|
-
it {
|
40
|
+
it { expect { transition }.to change(adapter.history, :count).by(1) }
|
41
41
|
|
42
42
|
context "the new transition" do
|
43
43
|
subject(:instance) { create }
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Statesman::Adapters::TypeSafeActiveRecordQueries, active_record: true do
|
6
|
+
def configure(klass, transition_class)
|
7
|
+
klass.send(:extend, described_class)
|
8
|
+
klass.configure_state_machine(
|
9
|
+
transition_class: transition_class,
|
10
|
+
initial_state: :initial,
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
prepare_model_table
|
16
|
+
prepare_transitions_table
|
17
|
+
prepare_other_model_table
|
18
|
+
prepare_other_transitions_table
|
19
|
+
|
20
|
+
Statesman.configure do
|
21
|
+
storage_adapter(Statesman::Adapters::ActiveRecord)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } }
|
26
|
+
|
27
|
+
let!(:model) do
|
28
|
+
model = MyActiveRecordModel.create
|
29
|
+
model.state_machine.transition_to(:succeeded)
|
30
|
+
model
|
31
|
+
end
|
32
|
+
|
33
|
+
let!(:other_model) do
|
34
|
+
model = MyActiveRecordModel.create
|
35
|
+
model.state_machine.transition_to(:failed)
|
36
|
+
model
|
37
|
+
end
|
38
|
+
|
39
|
+
let!(:initial_state_model) { MyActiveRecordModel.create }
|
40
|
+
|
41
|
+
let!(:returned_to_initial_model) do
|
42
|
+
model = MyActiveRecordModel.create
|
43
|
+
model.state_machine.transition_to(:failed)
|
44
|
+
model.state_machine.transition_to(:initial)
|
45
|
+
model
|
46
|
+
end
|
47
|
+
|
48
|
+
shared_examples "testing methods" do
|
49
|
+
before do
|
50
|
+
configure(MyActiveRecordModel, MyActiveRecordModelTransition)
|
51
|
+
configure(OtherActiveRecordModel, OtherActiveRecordModelTransition)
|
52
|
+
|
53
|
+
MyActiveRecordModel.send(:has_one, :other_active_record_model)
|
54
|
+
OtherActiveRecordModel.send(:belongs_to, :my_active_record_model)
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".in_state" do
|
58
|
+
context "given a single state" do
|
59
|
+
subject { MyActiveRecordModel.in_state(:succeeded) }
|
60
|
+
|
61
|
+
it { is_expected.to include model }
|
62
|
+
it { is_expected.to_not include other_model }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "given multiple states" do
|
66
|
+
subject { MyActiveRecordModel.in_state(:succeeded, :failed) }
|
67
|
+
|
68
|
+
it { is_expected.to include model }
|
69
|
+
it { is_expected.to include other_model }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "given the initial state" do
|
73
|
+
subject { MyActiveRecordModel.in_state(:initial) }
|
74
|
+
|
75
|
+
it { is_expected.to include initial_state_model }
|
76
|
+
it { is_expected.to include returned_to_initial_model }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "given an array of states" do
|
80
|
+
subject { MyActiveRecordModel.in_state(%i[succeeded failed]) }
|
81
|
+
|
82
|
+
it { is_expected.to include model }
|
83
|
+
it { is_expected.to include other_model }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "merging two queries" do
|
87
|
+
subject do
|
88
|
+
MyActiveRecordModel.in_state(:succeeded).
|
89
|
+
joins(:other_active_record_model).
|
90
|
+
merge(OtherActiveRecordModel.in_state(:initial))
|
91
|
+
end
|
92
|
+
|
93
|
+
it { is_expected.to be_empty }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe ".not_in_state" do
|
98
|
+
context "given a single state" do
|
99
|
+
subject { MyActiveRecordModel.not_in_state(:failed) }
|
100
|
+
|
101
|
+
it { is_expected.to include model }
|
102
|
+
it { is_expected.to_not include other_model }
|
103
|
+
end
|
104
|
+
|
105
|
+
context "given multiple states" do
|
106
|
+
subject(:not_in_state) { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
|
107
|
+
|
108
|
+
it do
|
109
|
+
expect(not_in_state).to contain_exactly(initial_state_model,
|
110
|
+
returned_to_initial_model)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "given an array of states" do
|
115
|
+
subject(:not_in_state) { MyActiveRecordModel.not_in_state(%i[succeeded failed]) }
|
116
|
+
|
117
|
+
it do
|
118
|
+
expect(not_in_state).to contain_exactly(initial_state_model,
|
119
|
+
returned_to_initial_model)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "with a custom name for the transition association" do
|
125
|
+
before do
|
126
|
+
# Switch to using OtherActiveRecordModelTransition, so the existing
|
127
|
+
# relation with MyActiveRecordModelTransition doesn't interfere with
|
128
|
+
# this spec.
|
129
|
+
MyActiveRecordModel.send(:has_many,
|
130
|
+
:custom_name,
|
131
|
+
class_name: "OtherActiveRecordModelTransition")
|
132
|
+
|
133
|
+
MyActiveRecordModel.class_eval do
|
134
|
+
def self.transition_class
|
135
|
+
OtherActiveRecordModelTransition
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe ".in_state" do
|
141
|
+
subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
|
142
|
+
|
143
|
+
specify { expect { query }.to_not raise_error }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "with a custom primary key for the model" do
|
148
|
+
before do
|
149
|
+
# Switch to using OtherActiveRecordModelTransition, so the existing
|
150
|
+
# relation with MyActiveRecordModelTransition doesn't interfere with
|
151
|
+
# this spec.
|
152
|
+
# Configure the relationship to use a different primary key,
|
153
|
+
MyActiveRecordModel.send(:has_many,
|
154
|
+
:custom_name,
|
155
|
+
class_name: "OtherActiveRecordModelTransition",
|
156
|
+
primary_key: :external_id)
|
157
|
+
|
158
|
+
MyActiveRecordModel.class_eval do
|
159
|
+
def self.transition_class
|
160
|
+
OtherActiveRecordModelTransition
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe ".in_state" do
|
166
|
+
subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
|
167
|
+
|
168
|
+
specify { expect { query }.to_not raise_error }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "after_commit transactional integrity" do
|
173
|
+
before do
|
174
|
+
MyStateMachine.class_eval do
|
175
|
+
cattr_accessor(:after_commit_callback_executed) { false }
|
176
|
+
|
177
|
+
after_transition(from: :initial, to: :succeeded, after_commit: true) do
|
178
|
+
# This leaks state in a testable way if transactional integrity is broken.
|
179
|
+
MyStateMachine.after_commit_callback_executed = true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
after do
|
185
|
+
MyStateMachine.class_eval do
|
186
|
+
callbacks[:after_commit] = []
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
let!(:model) do
|
191
|
+
MyActiveRecordModel.create
|
192
|
+
end
|
193
|
+
|
194
|
+
it do
|
195
|
+
expect do
|
196
|
+
ActiveRecord::Base.transaction do
|
197
|
+
model.state_machine.transition_to!(:succeeded)
|
198
|
+
raise ActiveRecord::Rollback
|
199
|
+
end
|
200
|
+
end.to_not change(MyStateMachine, :after_commit_callback_executed)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "using configuration method" do
|
206
|
+
include_examples "testing methods"
|
207
|
+
end
|
208
|
+
end
|
@@ -64,12 +64,18 @@ describe Statesman do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
describe "GuardFailedError" do
|
67
|
-
subject(:error) { Statesman::GuardFailedError.new("from", "to") }
|
67
|
+
subject(:error) { Statesman::GuardFailedError.new("from", "to", callback) }
|
68
|
+
|
69
|
+
let(:callback) { -> { "hello" } }
|
68
70
|
|
69
71
|
its(:message) do
|
70
72
|
is_expected.to eq("Guard on transition from: 'from' to 'to' returned false")
|
71
73
|
end
|
72
74
|
|
75
|
+
its(:backtrace) do
|
76
|
+
is_expected.to eq([callback.source_location.join(":")])
|
77
|
+
end
|
78
|
+
|
73
79
|
its "string matches its message" do
|
74
80
|
expect(error.to_s).to eq(error.message)
|
75
81
|
end
|
@@ -28,7 +28,7 @@ describe Statesman::Machine do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe ".remove_state" do
|
31
|
-
subject(:remove_state) {
|
31
|
+
subject(:remove_state) { machine.remove_state(:x) }
|
32
32
|
|
33
33
|
before do
|
34
34
|
machine.class_eval do
|
@@ -39,7 +39,7 @@ describe Statesman::Machine do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
it "removes the state" do
|
42
|
-
expect
|
42
|
+
expect { remove_state }.
|
43
43
|
to change(machine, :states).
|
44
44
|
from(match_array(%w[x y z])).
|
45
45
|
to(%w[y z])
|
@@ -49,7 +49,7 @@ describe Statesman::Machine do
|
|
49
49
|
before { machine.transition from: :x, to: :y }
|
50
50
|
|
51
51
|
it "removes the transition" do
|
52
|
-
expect
|
52
|
+
expect { remove_state }.
|
53
53
|
to change(machine, :successors).
|
54
54
|
from({ "x" => ["y"] }).
|
55
55
|
to({})
|
@@ -59,7 +59,7 @@ describe Statesman::Machine do
|
|
59
59
|
before { machine.transition from: :x, to: :z }
|
60
60
|
|
61
61
|
it "removes all transitions" do
|
62
|
-
expect
|
62
|
+
expect { remove_state }.
|
63
63
|
to change(machine, :successors).
|
64
64
|
from({ "x" => %w[y z] }).
|
65
65
|
to({})
|
@@ -71,7 +71,7 @@ describe Statesman::Machine do
|
|
71
71
|
before { machine.transition from: :y, to: :x }
|
72
72
|
|
73
73
|
it "removes the transition" do
|
74
|
-
expect
|
74
|
+
expect { remove_state }.
|
75
75
|
to change(machine, :successors).
|
76
76
|
from({ "y" => ["x"] }).
|
77
77
|
to({})
|
@@ -81,7 +81,7 @@ describe Statesman::Machine do
|
|
81
81
|
before { machine.transition from: :z, to: :x }
|
82
82
|
|
83
83
|
it "removes all transitions" do
|
84
|
-
expect
|
84
|
+
expect { remove_state }.
|
85
85
|
to change(machine, :successors).
|
86
86
|
from({ "y" => ["x"], "z" => ["x"] }).
|
87
87
|
to({})
|
@@ -104,7 +104,7 @@ describe Statesman::Machine do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it "removes the guard" do
|
107
|
-
expect
|
107
|
+
expect { remove_state }.
|
108
108
|
to change(machine, :callbacks).
|
109
109
|
from(a_hash_including(guards: match_array(guards))).
|
110
110
|
to(a_hash_including(guards: []))
|
@@ -125,7 +125,7 @@ describe Statesman::Machine do
|
|
125
125
|
end
|
126
126
|
|
127
127
|
it "removes the guard" do
|
128
|
-
expect
|
128
|
+
expect { remove_state }.
|
129
129
|
to change(machine, :callbacks).
|
130
130
|
from(a_hash_including(guards: match_array(guards))).
|
131
131
|
to(a_hash_including(guards: []))
|
@@ -935,10 +935,10 @@ describe Statesman::Machine do
|
|
935
935
|
it { is_expected.to be(:some_state) }
|
936
936
|
end
|
937
937
|
|
938
|
-
context "when it is
|
938
|
+
context "when it is unsuccessful" do
|
939
939
|
before do
|
940
940
|
allow(instance).to receive(:transition_to!).
|
941
|
-
and_raise(Statesman::GuardFailedError.new(:x, :some_state))
|
941
|
+
and_raise(Statesman::GuardFailedError.new(:x, :some_state, nil))
|
942
942
|
end
|
943
943
|
|
944
944
|
it { is_expected.to be_falsey }
|
@@ -976,20 +976,20 @@ describe Statesman::Machine do
|
|
976
976
|
end
|
977
977
|
|
978
978
|
context "with defined callbacks" do
|
979
|
-
let(:
|
980
|
-
let(:
|
979
|
+
let(:callback_one) { -> { "Hi" } }
|
980
|
+
let(:callback_two) { -> { "Bye" } }
|
981
981
|
|
982
982
|
before do
|
983
|
-
machine.send(definer, from: :x, to: :y, &
|
984
|
-
machine.send(definer, from: :y, to: :z, &
|
983
|
+
machine.send(definer, from: :x, to: :y, &callback_one)
|
984
|
+
machine.send(definer, from: :y, to: :z, &callback_two)
|
985
985
|
end
|
986
986
|
|
987
987
|
it "contains the relevant callback" do
|
988
|
-
expect(callbacks.map(&:callback)).to include(
|
988
|
+
expect(callbacks.map(&:callback)).to include(callback_one)
|
989
989
|
end
|
990
990
|
|
991
991
|
it "does not contain the irrelevant callback" do
|
992
|
-
expect(callbacks.map(&:callback)).to_not include(
|
992
|
+
expect(callbacks.map(&:callback)).to_not include(callback_two)
|
993
993
|
end
|
994
994
|
end
|
995
995
|
end
|