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