statesman 10.0.0 → 10.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|