statesman 1.3.1 → 2.0.0.rc1
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/.travis.yml +0 -1
- data/CHANGELOG.md +45 -19
- data/README.md +20 -11
- data/lib/generators/statesman/templates/active_record_transition_model.rb.erb +10 -0
- data/lib/statesman/adapters/active_record.rb +9 -10
- data/lib/statesman/adapters/active_record_queries.rb +3 -63
- data/lib/statesman/adapters/memory.rb +2 -2
- data/lib/statesman/adapters/mongoid.rb +7 -3
- data/lib/statesman/machine.rb +14 -53
- data/lib/statesman/version.rb +1 -1
- data/spec/spec_helper.rb +18 -11
- data/spec/statesman/adapters/active_record_queries_spec.rb +45 -119
- data/spec/statesman/adapters/active_record_spec.rb +43 -14
- data/spec/statesman/adapters/shared_examples.rb +5 -2
- data/spec/statesman/machine_spec.rb +55 -122
- data/spec/support/active_record.rb +28 -4
- data/statesman.gemspec +1 -1
- metadata +39 -49
- data/circle.yml +0 -9
- data/lib/generators/statesman/add_constraints_to_most_recent_generator.rb +0 -28
- data/lib/generators/statesman/add_most_recent_generator.rb +0 -25
- data/lib/generators/statesman/templates/add_constraints_to_most_recent_migration.rb.erb +0 -19
- data/lib/generators/statesman/templates/add_most_recent_migration.rb.erb +0 -9
- data/lib/statesman/event_transitions.rb +0 -15
- data/spec/generators/statesman/add_constraints_to_most_recent_generator_spec.rb +0 -43
- data/spec/generators/statesman/add_most_recent_generator_spec.rb +0 -35
data/lib/statesman/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "statesman"
|
2
2
|
require "sqlite3"
|
3
|
+
require "mysql2"
|
4
|
+
require "pg"
|
5
|
+
require "mongoid"
|
3
6
|
require "active_record"
|
4
7
|
# We have to include all of Rails to make rspec-rails work
|
5
8
|
require "rails"
|
@@ -8,7 +11,6 @@ require "action_dispatch"
|
|
8
11
|
require "action_controller"
|
9
12
|
require "rspec/rails"
|
10
13
|
require "support/active_record"
|
11
|
-
require "mongoid"
|
12
14
|
require "rspec/its"
|
13
15
|
|
14
16
|
RSpec.configure do |config|
|
@@ -17,16 +19,28 @@ RSpec.configure do |config|
|
|
17
19
|
|
18
20
|
config.order = "random"
|
19
21
|
|
22
|
+
def connection_failure
|
23
|
+
if defined?(Moped)
|
24
|
+
Moped::Errors::ConnectionFailure
|
25
|
+
else
|
26
|
+
Mongo::Error::NoServerAvailable
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
# Try a mongo connection at the start of the suite and raise if it fails
|
21
31
|
begin
|
22
32
|
Mongoid.configure do |mongo_config|
|
23
|
-
|
24
|
-
|
33
|
+
if defined?(Moped)
|
34
|
+
mongo_config.connect_to("statesman_test")
|
35
|
+
mongo_config.sessions["default"]["options"]["max_retries"] = 2
|
36
|
+
else
|
37
|
+
mongo_config.connect_to("statesman_test", server_selection_timeout: 2)
|
38
|
+
end
|
25
39
|
end
|
26
40
|
# Attempting a mongo operation will trigger 2 retries then throw an
|
27
41
|
# exception if mongo is not running.
|
28
42
|
Mongoid.purge! unless config.exclusion_filter[:mongo]
|
29
|
-
rescue
|
43
|
+
rescue connection_failure => error
|
30
44
|
puts "The spec suite requires MongoDB to be installed and running locally"
|
31
45
|
puts "Mongo dependent specs can be filtered with rspec --tag '~mongo'"
|
32
46
|
raise(error)
|
@@ -71,13 +85,6 @@ RSpec.configure do |config|
|
|
71
85
|
end
|
72
86
|
end
|
73
87
|
|
74
|
-
def drop_most_recent_column
|
75
|
-
silence_stream(STDOUT) do
|
76
|
-
DropMostRecentColumn.migrate(:up)
|
77
|
-
MyActiveRecordModelTransition.reset_column_information
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
88
|
def prepare_other_model_table
|
82
89
|
silence_stream(STDOUT) do
|
83
90
|
CreateOtherActiveRecordModelMigration.migrate(:up)
|
@@ -61,129 +61,66 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
61
61
|
model
|
62
62
|
end
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
subject { MyActiveRecordModel.in_state(:succeeded) }
|
68
|
-
|
69
|
-
it { is_expected.to include model }
|
70
|
-
it { is_expected.not_to include other_model }
|
71
|
-
its(:to_sql) { is_expected.to include('.most_recent ') }
|
72
|
-
end
|
64
|
+
describe ".in_state" do
|
65
|
+
context "given a single state" do
|
66
|
+
subject { MyActiveRecordModel.in_state(:succeeded) }
|
73
67
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
it { is_expected.to include model }
|
78
|
-
it { is_expected.to include other_model }
|
79
|
-
end
|
68
|
+
it { is_expected.to include model }
|
69
|
+
it { is_expected.not_to include other_model }
|
70
|
+
end
|
80
71
|
|
81
|
-
|
82
|
-
|
72
|
+
context "given multiple states" do
|
73
|
+
subject { MyActiveRecordModel.in_state(:succeeded, :failed) }
|
83
74
|
|
84
|
-
|
85
|
-
|
86
|
-
|
75
|
+
it { is_expected.to include model }
|
76
|
+
it { is_expected.to include other_model }
|
77
|
+
end
|
87
78
|
|
88
|
-
|
89
|
-
|
79
|
+
context "given the initial state" do
|
80
|
+
subject { MyActiveRecordModel.in_state(:initial) }
|
90
81
|
|
91
|
-
|
92
|
-
|
93
|
-
|
82
|
+
it { is_expected.to include initial_state_model }
|
83
|
+
it { is_expected.to include returned_to_initial_model }
|
84
|
+
end
|
94
85
|
|
95
|
-
|
96
|
-
|
97
|
-
MyActiveRecordModel.in_state(:succeeded).
|
98
|
-
joins(:other_active_record_model).
|
99
|
-
merge(OtherActiveRecordModel.in_state(:initial))
|
100
|
-
end
|
86
|
+
context "given an array of states" do
|
87
|
+
subject { MyActiveRecordModel.in_state([:succeeded, :failed]) }
|
101
88
|
|
102
|
-
|
103
|
-
|
89
|
+
it { is_expected.to include model }
|
90
|
+
it { is_expected.to include other_model }
|
104
91
|
end
|
105
92
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
its(:to_sql) { is_expected.to include('.most_recent ') }
|
93
|
+
context "merging two queries" do
|
94
|
+
subject do
|
95
|
+
MyActiveRecordModel.in_state(:succeeded).
|
96
|
+
joins(:other_active_record_model).
|
97
|
+
merge(OtherActiveRecordModel.in_state(:initial))
|
112
98
|
end
|
113
99
|
|
114
|
-
|
115
|
-
subject { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
|
116
|
-
it do
|
117
|
-
is_expected.to match_array([initial_state_model,
|
118
|
-
returned_to_initial_model])
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
context "given an array of states" do
|
123
|
-
subject { MyActiveRecordModel.not_in_state([:succeeded, :failed]) }
|
124
|
-
it do
|
125
|
-
is_expected.to match_array([initial_state_model,
|
126
|
-
returned_to_initial_model])
|
127
|
-
end
|
128
|
-
end
|
100
|
+
it { is_expected.to be_empty }
|
129
101
|
end
|
130
102
|
end
|
131
103
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
subject { MyActiveRecordModel.in_state(:succeeded) }
|
138
|
-
|
139
|
-
it { is_expected.to include model }
|
140
|
-
its(:to_sql) { is_expected.not_to include('.most_recent ') }
|
141
|
-
end
|
142
|
-
|
143
|
-
context "given multiple states" do
|
144
|
-
subject { MyActiveRecordModel.in_state(:succeeded, :failed) }
|
145
|
-
|
146
|
-
it { is_expected.to include model }
|
147
|
-
it { is_expected.to include other_model }
|
148
|
-
end
|
149
|
-
|
150
|
-
context "given the initial state" do
|
151
|
-
subject { MyActiveRecordModel.in_state(:initial) }
|
152
|
-
|
153
|
-
it { is_expected.to include initial_state_model }
|
154
|
-
it { is_expected.to include returned_to_initial_model }
|
155
|
-
end
|
156
|
-
|
157
|
-
context "given an array of states" do
|
158
|
-
subject { MyActiveRecordModel.in_state([:succeeded, :failed]) }
|
159
|
-
|
160
|
-
it { is_expected.to include model }
|
161
|
-
it { is_expected.to include other_model }
|
162
|
-
end
|
104
|
+
describe ".not_in_state" do
|
105
|
+
context "given a single state" do
|
106
|
+
subject { MyActiveRecordModel.not_in_state(:failed) }
|
107
|
+
it { is_expected.to include model }
|
108
|
+
it { is_expected.not_to include other_model }
|
163
109
|
end
|
164
110
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
its(:to_sql) { is_expected.not_to include('.most_recent ') }
|
171
|
-
end
|
172
|
-
|
173
|
-
context "given multiple states" do
|
174
|
-
subject { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
|
175
|
-
it do
|
176
|
-
is_expected.to match_array([initial_state_model,
|
177
|
-
returned_to_initial_model])
|
178
|
-
end
|
111
|
+
context "given multiple states" do
|
112
|
+
subject { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
|
113
|
+
it do
|
114
|
+
is_expected.to match_array([initial_state_model,
|
115
|
+
returned_to_initial_model])
|
179
116
|
end
|
117
|
+
end
|
180
118
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
end
|
119
|
+
context "given an array of states" do
|
120
|
+
subject { MyActiveRecordModel.not_in_state([:succeeded, :failed]) }
|
121
|
+
it do
|
122
|
+
is_expected.to match_array([initial_state_model,
|
123
|
+
returned_to_initial_model])
|
187
124
|
end
|
188
125
|
end
|
189
126
|
end
|
@@ -200,20 +137,9 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
200
137
|
end
|
201
138
|
end
|
202
139
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
specify { expect { query }.to_not raise_error }
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
context "without a most_recent column" do
|
211
|
-
before { drop_most_recent_column }
|
212
|
-
|
213
|
-
describe ".in_state" do
|
214
|
-
subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
|
215
|
-
specify { expect { query }.to_not raise_error }
|
216
|
-
end
|
140
|
+
describe ".in_state" do
|
141
|
+
subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
|
142
|
+
specify { expect { query }.to_not raise_error }
|
217
143
|
end
|
218
144
|
end
|
219
145
|
end
|
@@ -131,7 +131,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
-
|
134
|
+
describe "updating the most_recent column" do
|
135
135
|
subject { create }
|
136
136
|
|
137
137
|
context "with no previous transition" do
|
@@ -148,17 +148,31 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
148
148
|
from(true).to be_falsey
|
149
149
|
end
|
150
150
|
|
151
|
-
context "and the parent model is
|
152
|
-
before do
|
153
|
-
|
154
|
-
|
155
|
-
|
151
|
+
context "and a query on the parent model's state is made" do
|
152
|
+
context "in a before action" do
|
153
|
+
it "still has the old state" do
|
154
|
+
allow(observer).to receive(:execute) do |phase|
|
155
|
+
next unless phase == :before
|
156
|
+
expect(
|
157
|
+
model.transitions.where(most_recent: true).first.to_state
|
158
|
+
).to eq("y")
|
156
159
|
end
|
160
|
+
|
161
|
+
adapter.create(:y, :z)
|
157
162
|
end
|
158
163
|
end
|
159
164
|
|
160
|
-
|
161
|
-
|
165
|
+
context "in an after action" do
|
166
|
+
it "still has the old state" do
|
167
|
+
allow(observer).to receive(:execute) do |phase|
|
168
|
+
next unless phase == :after
|
169
|
+
expect(
|
170
|
+
model.transitions.where(most_recent: true).first.to_state
|
171
|
+
).to eq("z")
|
172
|
+
end
|
173
|
+
|
174
|
+
adapter.create(:y, :z)
|
175
|
+
end
|
162
176
|
end
|
163
177
|
end
|
164
178
|
end
|
@@ -175,11 +189,6 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
175
189
|
end
|
176
190
|
end
|
177
191
|
end
|
178
|
-
|
179
|
-
context "when the transition_class doesn't have a most_recent column" do
|
180
|
-
before { drop_most_recent_column }
|
181
|
-
it { is_expected.to_not raise_exception }
|
182
|
-
end
|
183
192
|
end
|
184
193
|
|
185
194
|
describe "#last" do
|
@@ -198,12 +207,32 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
198
207
|
adapter.last
|
199
208
|
end
|
200
209
|
|
201
|
-
context "
|
210
|
+
context "after then creating a new transition" do
|
202
211
|
before { adapter.create(:y, :z, []) }
|
203
212
|
it "retrieves the new transition from the database" do
|
204
213
|
expect(adapter.last.to_state).to eq("z")
|
205
214
|
end
|
206
215
|
end
|
216
|
+
|
217
|
+
context "when a new transition has been created elsewhere" do
|
218
|
+
let(:alternate_adapter) do
|
219
|
+
described_class.new(MyActiveRecordModelTransition, model, observer)
|
220
|
+
end
|
221
|
+
|
222
|
+
before { alternate_adapter.create(:y, :z, []) }
|
223
|
+
|
224
|
+
it "still returns the cached value" do
|
225
|
+
expect_any_instance_of(MyActiveRecordModel).
|
226
|
+
to receive(:my_active_record_model_transitions).never
|
227
|
+
expect(adapter.last.to_state).to eq("y")
|
228
|
+
end
|
229
|
+
|
230
|
+
context "when explitly not using the cache" do
|
231
|
+
it "still returns the cached value" do
|
232
|
+
expect(adapter.last(force_reload: true).to_state).to eq("z")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
207
236
|
end
|
208
237
|
|
209
238
|
context "with a pre-fetched transition history" do
|
@@ -47,12 +47,12 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
|
|
47
47
|
end
|
48
48
|
|
49
49
|
context "with no previous transition" do
|
50
|
-
its(:sort_key) { is_expected.to be(
|
50
|
+
its(:sort_key) { is_expected.to be(10) }
|
51
51
|
end
|
52
52
|
|
53
53
|
context "with a previous transition" do
|
54
54
|
before { adapter.create(from, to) }
|
55
|
-
its(:sort_key) { is_expected.to be(
|
55
|
+
its(:sort_key) { is_expected.to be(20) }
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -118,5 +118,8 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
|
|
118
118
|
|
119
119
|
it { is_expected.to be_a(transition_class) }
|
120
120
|
specify { expect(adapter.last.to_state.to_sym).to eq(:z) }
|
121
|
+
specify do
|
122
|
+
expect(adapter.last(force_reload: true).to_state.to_sym).to eq(:z)
|
123
|
+
end
|
121
124
|
end
|
122
125
|
end
|
@@ -374,6 +374,61 @@ describe Statesman::Machine do
|
|
374
374
|
end
|
375
375
|
end
|
376
376
|
|
377
|
+
describe "#in_state?" do
|
378
|
+
before do
|
379
|
+
machine.class_eval do
|
380
|
+
state :x, initial: true
|
381
|
+
state :y
|
382
|
+
transition from: :x, to: :y
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
let(:instance) { machine.new(my_model) }
|
387
|
+
subject { instance.in_state?(state) }
|
388
|
+
before { instance.transition_to!(:y) }
|
389
|
+
|
390
|
+
context "when machine is in given state" do
|
391
|
+
let(:state) { "y" }
|
392
|
+
it { is_expected.to eq(true) }
|
393
|
+
end
|
394
|
+
|
395
|
+
context "when machine is not in given state" do
|
396
|
+
let(:state) { "x" }
|
397
|
+
it { is_expected.to eq(false) }
|
398
|
+
end
|
399
|
+
|
400
|
+
context "when given a symbol" do
|
401
|
+
let(:state) { :y }
|
402
|
+
it { is_expected.to eq(true) }
|
403
|
+
end
|
404
|
+
|
405
|
+
context "when given multiple states" do
|
406
|
+
context "when given multiple arguments" do
|
407
|
+
context "when one of the states is the current state" do
|
408
|
+
subject { instance.in_state?(:x, :y) }
|
409
|
+
it { is_expected.to eq(true) }
|
410
|
+
end
|
411
|
+
|
412
|
+
context "when none of the states are the current state" do
|
413
|
+
subject { instance.in_state?(:x, :z) }
|
414
|
+
it { is_expected.to eq(false) }
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
context "when given an array" do
|
419
|
+
context "when one of the states is the current state" do
|
420
|
+
subject { instance.in_state?([:x, :y]) }
|
421
|
+
it { is_expected.to eq(true) }
|
422
|
+
end
|
423
|
+
|
424
|
+
context "when none of the states are the current state" do
|
425
|
+
subject { instance.in_state?([:x, :z]) }
|
426
|
+
it { is_expected.to eq(false) }
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
377
432
|
describe "#allowed_transitions" do
|
378
433
|
before do
|
379
434
|
machine.class_eval do
|
@@ -627,126 +682,4 @@ describe Statesman::Machine do
|
|
627
682
|
describe "#after_callbacks_for" do
|
628
683
|
it_behaves_like "a callback filter", :after_transition, :after
|
629
684
|
end
|
630
|
-
|
631
|
-
describe "#event" do
|
632
|
-
before do
|
633
|
-
machine.class_eval do
|
634
|
-
state :x, initial: true
|
635
|
-
state :y
|
636
|
-
state :z
|
637
|
-
|
638
|
-
event :event_1 do
|
639
|
-
transition from: :x, to: :y
|
640
|
-
end
|
641
|
-
|
642
|
-
event :event_2 do
|
643
|
-
transition from: :y, to: :z
|
644
|
-
end
|
645
|
-
end
|
646
|
-
end
|
647
|
-
|
648
|
-
let(:instance) { machine.new(my_model) }
|
649
|
-
|
650
|
-
context "when the state cannot be transitioned to" do
|
651
|
-
it "raises an error" do
|
652
|
-
expect { instance.trigger!(:event_2) }.
|
653
|
-
to raise_error(Statesman::TransitionFailedError)
|
654
|
-
end
|
655
|
-
end
|
656
|
-
|
657
|
-
context "when the state can be transitioned to" do
|
658
|
-
it "changes state" do
|
659
|
-
instance.trigger!(:event_1)
|
660
|
-
expect(instance.current_state).to eq("y")
|
661
|
-
end
|
662
|
-
|
663
|
-
it "creates a new transition object" do
|
664
|
-
expect { instance.trigger!(:event_1) }.
|
665
|
-
to change(instance.history, :count).by(1)
|
666
|
-
|
667
|
-
expect(instance.history.first).
|
668
|
-
to be_a(Statesman::Adapters::MemoryTransition)
|
669
|
-
expect(instance.history.first.to_state).to eq("y")
|
670
|
-
end
|
671
|
-
|
672
|
-
it "sends metadata to the transition object" do
|
673
|
-
meta = { "my" => "hash" }
|
674
|
-
instance.trigger!(:event_1, meta)
|
675
|
-
expect(instance.history.first.metadata).to eq(meta)
|
676
|
-
end
|
677
|
-
|
678
|
-
it "sets an empty hash as the metadata if not specified" do
|
679
|
-
instance.trigger!(:event_1)
|
680
|
-
expect(instance.history.first.metadata).to eq({})
|
681
|
-
end
|
682
|
-
|
683
|
-
it "returns true" do
|
684
|
-
expect(instance.trigger!(:event_1)).to eq(true)
|
685
|
-
end
|
686
|
-
|
687
|
-
context "with a guard" do
|
688
|
-
let(:result) { true }
|
689
|
-
# rubocop:disable UnusedBlockArgument
|
690
|
-
let(:guard_cb) { ->(*args) { result } }
|
691
|
-
# rubocop:enable UnusedBlockArgument
|
692
|
-
before { machine.guard_transition(from: :x, to: :y, &guard_cb) }
|
693
|
-
|
694
|
-
context "and an object to act on" do
|
695
|
-
let(:instance) { machine.new(my_model) }
|
696
|
-
|
697
|
-
it "passes the object to the guard" do
|
698
|
-
expect(guard_cb).to receive(:call).once.
|
699
|
-
with(my_model, instance.last_transition, {}).and_return(true)
|
700
|
-
instance.trigger!(:event_1)
|
701
|
-
end
|
702
|
-
end
|
703
|
-
|
704
|
-
context "which passes" do
|
705
|
-
it "changes state" do
|
706
|
-
expect { instance.trigger!(:event_1) }.
|
707
|
-
to change { instance.current_state }.to("y")
|
708
|
-
end
|
709
|
-
end
|
710
|
-
|
711
|
-
context "which fails" do
|
712
|
-
let(:result) { false }
|
713
|
-
|
714
|
-
it "raises an exception" do
|
715
|
-
expect { instance.trigger!(:event_1) }.
|
716
|
-
to raise_error(Statesman::GuardFailedError)
|
717
|
-
end
|
718
|
-
end
|
719
|
-
end
|
720
|
-
end
|
721
|
-
end
|
722
|
-
|
723
|
-
describe "#available_events" do
|
724
|
-
before do
|
725
|
-
machine.class_eval do
|
726
|
-
state :x, initial: true
|
727
|
-
state :y
|
728
|
-
state :z
|
729
|
-
|
730
|
-
event :event_1 do
|
731
|
-
transition from: :x, to: :y
|
732
|
-
end
|
733
|
-
|
734
|
-
event :event_2 do
|
735
|
-
transition from: :y, to: :z
|
736
|
-
end
|
737
|
-
|
738
|
-
event :event_3 do
|
739
|
-
transition from: :x, to: :y
|
740
|
-
transition from: :y, to: :x
|
741
|
-
end
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
|
-
let(:instance) { machine.new(my_model) }
|
746
|
-
it "should return list of available events for the current state" do
|
747
|
-
expect(instance.available_events).to eq([:event_1, :event_3])
|
748
|
-
instance.trigger!(:event_1)
|
749
|
-
expect(instance.available_events).to eq([:event_2, :event_3])
|
750
|
-
end
|
751
|
-
end
|
752
685
|
end
|