1
0
Fork 0
mirror of https://github.com/aasm/aasm synced 2023-03-27 23:22:41 -04:00

more tests

This commit is contained in:
Thorsten Böttger 2015-06-26 19:46:58 +12:00
parent 719dadf1ff
commit 206b1991bc
18 changed files with 750 additions and 152 deletions

View file

@ -3,7 +3,23 @@
## version 4.3 ## version 4.3
* add support for multiple state machines per class * add support for multiple state machines per class
* check all tests
* what happen's if someone accesses `aasm`, but has defined a
state machine for `aasm(:my_name)`?
* persistence
* _ActiveRecord_
* _Mongoid_
* _MongoMapper_
* _Sequel_
* documentation * documentation
* events are chained * silence warnings?
* :default state machine won't be provided, if state machine name is used
* if used raise an error # Changes so far
## version 4.3
* add support for multiple state machines per class
* class- and instance-level `aasm` methods accept a state machine selector
(aka the state machine _name_)
* if no selector/name is provided, `:default` will be used
* duplicate definitions of states and events will issue warnings

View file

@ -67,7 +67,7 @@ module AASM
@state_machine.add_state(name, @klass, options) @state_machine.add_state(name, @klass, options)
if @klass.instance_methods.include?("#{name}?") if @klass.instance_methods.include?("#{name}?")
warn "The state name #{name} is already used!" warn "#{@klass.name}: The state name #{name} is already used!"
end end
@klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1 @klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
@ -86,7 +86,7 @@ module AASM
@state_machine.add_event(name, options, &block) @state_machine.add_event(name, options, &block)
if @klass.instance_methods.include?("may_#{name}?".to_sym) if @klass.instance_methods.include?("may_#{name}?".to_sym)
warn "The event name #{name} is already used!" warn "#{@klass.name}: The event name #{name} is already used!"
end end
# an addition over standard aasm so that, before firing an event, you can ask # an addition over standard aasm so that, before firing an event, you can ask

View file

@ -86,3 +86,137 @@ class ComplexExample
phrase == :please phrase == :please
end end
end end
class ComplexExampleMultiple
include AASM
attr_accessor :activation_code, :activated_at, :deleted_at
aasm(:left) do
state :passive
state :pending, :initial => true, :before_enter => :make_activation_code
state :active, :before_enter => :do_activate
state :suspended
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
state :waiting
event :left_register do
transitions :from => :passive, :to => :pending do
guard do
can_register?
end
end
end
event :left_activate do
transitions :from => :pending, :to => :active
end
event :left_suspend do
transitions :from => [:passive, :pending, :active], :to => :suspended
end
event :left_delete do
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
end
# a dummy event that can never happen
event :left_unpassify do
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
end
event :left_unsuspend do
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
transitions :from => :suspended, :to => :passive
end
event :left_wait do
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
end
end
aasm(:right) do
state :passive
state :pending, :initial => true, :before_enter => :make_activation_code
state :active, :before_enter => :do_activate
state :suspended
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
state :waiting
event :right_register do
transitions :from => :passive, :to => :pending do
guard do
can_register?
end
end
end
event :right_activate do
transitions :from => :pending, :to => :active
end
event :right_suspend do
transitions :from => [:passive, :pending, :active], :to => :suspended
end
event :right_delete do
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
end
# a dummy event that can never happen
event :right_unpassify do
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
end
event :right_unsuspend do
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
transitions :from => :suspended, :to => :passive
end
event :right_wait do
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
end
end # right
def initialize
# the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
# lets do something similar here for testing purposes.
aasm(:left).enter_initial_state
aasm(:right).enter_initial_state
end
def make_activation_code
@activation_code = @activation_code ? @activation_code + '2' : '1'
end
def do_activate
@activated_at = Time.now
@activation_code = nil
end
def do_delete
@deleted_at = Time.now
end
def do_undelete
@deleted_at = false
end
def can_register?
true
end
def has_activated?
!!@activated_at
end
def has_activation_code?
!!@activation_code
end
def if_polite?(phrase = nil)
phrase == :please
end
end

View file

@ -1,133 +0,0 @@
class ComplexMultipleExample
include AASM
attr_accessor :activation_code, :activated_at, :deleted_at
aasm(:left) do
state :passive
state :pending, :initial => true, :before_enter => :make_activation_code
state :active, :before_enter => :do_activate
state :suspended
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
state :waiting
event :left_register do
transitions :from => :passive, :to => :pending do
guard do
can_register?
end
end
end
event :left_activate do
transitions :from => :pending, :to => :active
end
event :left_suspend do
transitions :from => [:passive, :pending, :active], :to => :suspended
end
event :left_delete do
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
end
# a dummy event that can never happen
event :left_unpassify do
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
end
event :left_unsuspend do
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
transitions :from => :suspended, :to => :passive
end
event :left_wait do
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
end
end
aasm(:right) do
state :passive
state :pending, :initial => true, :before_enter => :make_activation_code
state :active, :before_enter => :do_activate
state :suspended
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
state :waiting
event :right_register do
transitions :from => :passive, :to => :pending do
guard do
can_register?
end
end
end
event :right_activate do
transitions :from => :pending, :to => :active
end
event :right_suspend do
transitions :from => [:passive, :pending, :active], :to => :suspended
end
event :right_delete do
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
end
# a dummy event that can never happen
event :right_unpassify do
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
end
event :right_unsuspend do
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
transitions :from => :suspended, :to => :passive
end
event :right_wait do
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
end
end # right
def initialize
# the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
# lets do something similar here for testing purposes.
aasm(:left).enter_initial_state
aasm(:right).enter_initial_state
end
def make_activation_code
@activation_code = @activation_code ? @activation_code + '2' : '1'
end
def do_activate
@activated_at = Time.now
@activation_code = nil
end
def do_delete
@deleted_at = Time.now
end
def do_undelete
@deleted_at = false
end
def can_register?
true
end
def has_activated?
!!@activated_at
end
def has_activation_code?
!!@activation_code
end
def if_polite?(phrase = nil)
phrase == :please
end
end

View file

@ -34,8 +34,55 @@ class Conversation
@persister = persister @persister = persister
end end
private private
def aasm_read_state
@persister.read_state
end
def aasm_write_state(state)
@persister.write_state(state)
end
end
class ConversationMultiple
include AASM
aasm(:left) do
state :needs_attention, :initial => true
state :read
state :closed
state :awaiting_response
state :junk
event :new_message do
end
event :view do
transitions :to => :read, :from => [:needs_attention]
end
event :reply do
end
event :close do
transitions :to => :closed, :from => [:read, :awaiting_response]
end
event :junk do
transitions :to => :junk, :from => [:read]
end
event :unjunk do
end
end
def initialize(persister)
@persister = persister
end
private
def aasm_read_state def aasm_read_state
@persister.read_state @persister.read_state
end end
@ -43,5 +90,4 @@ class Conversation
def aasm_write_state(state) def aasm_write_state(state)
@persister.write_state(state) @persister.write_state(state)
end end
end end

View file

@ -33,3 +33,60 @@ class FooTwo < Foo
state :foo state :foo
end end
end end
class FooMultiple
include AASM
aasm(:left) do
state :open, :initial => true, :before_exit => :before_exit
state :closed, :before_enter => :before_enter
state :final
event :close, :success => :success_callback do
transitions :from => [:open], :to => [:closed]
end
event :null do
transitions :from => [:open], :to => [:closed, :final], :guard => :always_false
end
end
aasm(:right, :column => :right) do
state :green, :initial => true
state :yellow
state :red
event :green do
transitions :from => [:yellow], :to => :green
end
event :yellow do
transitions :from => [:green, :red], :to => :yellow
end
event :red do
transitions :from => [:yellow], :to => :red
end
end
def always_false
false
end
def success_callback
end
def before_enter
end
def before_exit
end
end
class FooTwoMultiple < FooMultiple
include AASM
aasm(:left) do
state :foo
end
aasm(:right) do
state :bar
end
end

View file

@ -1,5 +1,6 @@
class FooMultiple class FooCallbackMultiple
include AASM include AASM
aasm(:left) do aasm(:left) do
state :open, :initial => true, :before_exit => :before_exit state :open, :initial => true, :before_exit => :before_exit
state :closed, :before_enter => :before_enter state :closed, :before_enter => :before_enter
@ -14,6 +15,22 @@ class FooMultiple
end end
end end
aasm(:right, :column => :right) do
state :green, :initial => true
state :yellow
state :red
event :green do
transitions :from => [:yellow], :to => :green
end
event :yellow do
transitions :from => [:green, :red], :to => :yellow
end
event :red do
transitions :from => [:yellow], :to => :red
end
end
def always_false def always_false
false false
end end
@ -26,10 +43,3 @@ class FooMultiple
def before_exit def before_exit
end end
end end
class FooTwoMultiple < FooMultiple
include AASM
aasm(:left) do
state :foo
end
end

View file

@ -0,0 +1,48 @@
class GuardianMultiple
include AASM
aasm(:left) do
state :alpha, :initial => true
state :beta
event :use_one_guard_that_succeeds do
transitions :from => :alpha, :to => :beta, :guard => :succeed
end
event :use_one_guard_that_fails do
transitions :from => :alpha, :to => :beta, :guard => :fail
end
event :use_guards_that_succeed do
transitions :from => :alpha, :to => :beta, :guards => [:succeed, :another_succeed]
end
event :use_guards_where_the_first_fails do
transitions :from => :alpha, :to => :beta, :guards => [:succeed, :fail]
end
event :use_guards_where_the_second_fails do
transitions :from => :alpha, :to => :beta, :guards => [:fail, :succeed]
end
event :use_event_guards_that_succeed, :guards => [:succeed, :another_succeed] do
transitions :from => :alpha, :to => :beta
end
event :use_event_and_transition_guards_that_succeed, :guards => [:succeed, :another_succeed] do
transitions :from => :alpha, :to => :beta, :guards => [:more_succeed]
end
event :use_event_guards_where_the_first_fails, :guards => [:succeed, :fail] do
transitions :from => :alpha, :to => :beta
end
event :use_event_guards_where_the_second_fails, :guards => [:fail, :succeed] do
transitions :from => :alpha, :to => :beta, :guard => :another_succeed
end
event :use_event_and_transition_guards_where_third_fails, :guards => [:succeed, :another_succeed] do
transitions :from => :alpha, :to => :beta, :guards => [:fail]
end
end
def fail; false; end
def succeed; true; end
def another_succeed; true; end
def more_succeed; true; end
end

View file

@ -13,3 +13,19 @@ class InitialStateProc
def initialize(balance = 0); self.balance = balance; end def initialize(balance = 0); self.balance = balance; end
def rich?; self.balance >= RICH; end def rich?; self.balance >= RICH; end
end end
class InitialStateProcMultiple
RICH = 1_000_000
attr_accessor :balance
include AASM
aasm(:left) do
state :retired
state :selling_bad_mortgages
initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
end
def initialize(balance = 0); self.balance = balance; end
def rich?; self.balance >= RICH; end
end

View file

@ -10,3 +10,16 @@ class NoInitialState
end end
end end
end end
class NoInitialStateMultiple
include AASM
aasm(:left) do
state :read
state :ended
event :foo do
transitions :to => :ended, :from => [:read]
end
end
end

View file

@ -0,0 +1,29 @@
class ParametrisedEventMultiple
include AASM
aasm(:left) do
state :sleeping, :initial => true
state :showering
state :working
state :dating
state :prettying_up
event :wakeup do
transitions :from => :sleeping, :to => [:showering, :working]
end
event :dress do
transitions :from => :sleeping, :to => :working, :after => :wear_clothes
transitions :from => :showering, :to => [:working, :dating], :after => Proc.new { |*args| wear_clothes(*args) }
transitions :from => :showering, :to => :prettying_up, :after => [:condition_hair, :fix_hair]
end
end
def wear_clothes(shirt_color, trouser_type=nil)
end
def condition_hair
end
def fix_hair
end
end

View file

@ -9,3 +9,15 @@ class ValidStateName
end end
end end
end end
class ValidStateNameMultiple
include AASM
aasm(:left) do
state :invalid, :initial => true
state :valid
event :valid do
transitions :to => :valid, :from => [:invalid]
end
end
end

View file

@ -185,7 +185,7 @@ end # callbacks for the new DSL
describe 'event callbacks' do describe 'event callbacks' do
describe "with an error callback defined" do describe "with an error callback defined" do
before do before do
class FooMultiple class FooCallbackMultiple
# this hack is needed to allow testing of parameters, since RSpec # this hack is needed to allow testing of parameters, since RSpec
# destroys a method's arity when mocked # destroys a method's arity when mocked
attr_accessor :data attr_accessor :data
@ -197,7 +197,7 @@ describe 'event callbacks' do
end end
end end
@foo = FooMultiple.new @foo = FooCallbackMultiple.new
end end
context "error_callback defined" do context "error_callback defined" do

View file

@ -1,7 +1,7 @@
require 'spec_helper' require 'spec_helper'
describe 'on initialization' do describe 'on initialization' do
let(:auth) {ComplexMultipleExample.new} let(:auth) {ComplexExampleMultiple.new}
it 'should be in the pending state' do it 'should be in the pending state' do
expect(auth.aasm(:left).current_state).to eq(:pending) expect(auth.aasm(:left).current_state).to eq(:pending)
@ -15,7 +15,7 @@ describe 'on initialization' do
end end
describe 'when being unsuspended' do describe 'when being unsuspended' do
let(:auth) {ComplexMultipleExample.new} let(:auth) {ComplexExampleMultiple.new}
it 'should be able to unsuspend' do it 'should be able to unsuspend' do
auth.left_activate! auth.left_activate!

View file

@ -0,0 +1,73 @@
require 'spec_helper'
describe 'current event' do
let(:pe) {ParametrisedEventMultiple.new}
it 'if no event has been triggered' do
expect(pe.aasm(:left).current_event).to be_nil
end
it 'if a event has been triggered' do
pe.wakeup
expect(pe.aasm(:left).current_event).to eql :wakeup
end
it 'if no event has been triggered' do
pe.wakeup!
expect(pe.aasm(:left).current_event).to eql :wakeup!
end
end
describe 'parametrised events' do
let(:pe) {ParametrisedEventMultiple.new}
it 'should transition to specified next state (sleeping to showering)' do
pe.wakeup!(:showering)
expect(pe.aasm(:left).current_state).to eq(:showering)
end
it 'should transition to specified next state (sleeping to working)' do
pe.wakeup!(:working)
expect(pe.aasm(:left).current_state).to eq(:working)
end
it 'should transition to default (first or showering) state' do
pe.wakeup!
expect(pe.aasm(:left).current_state).to eq(:showering)
end
it 'should transition to default state when :after transition invoked' do
pe.dress!(nil, 'purple', 'dressy')
expect(pe.aasm(:left).current_state).to eq(:working)
end
it 'should call :after transition method with args' do
pe.wakeup!(:showering)
expect(pe).to receive(:wear_clothes).with('blue', 'jeans')
pe.dress!(:working, 'blue', 'jeans')
end
it 'should call :after transition proc' do
pe.wakeup!(:showering)
expect(pe).to receive(:wear_clothes).with('purple', 'slacks')
pe.dress!(:dating, 'purple', 'slacks')
end
it 'should call :after transition with an array of methods' do
pe.wakeup!(:showering)
expect(pe).to receive(:condition_hair)
expect(pe).to receive(:fix_hair)
pe.dress!(:prettying_up)
end
end
describe 'event firing without persistence' do
it 'should attempt to persist if aasm_write_state is defined' do
foo = Foo.new
def foo.aasm_write_state; end
expect(foo).to be_open
expect(foo).to receive(:aasm_write_state_without_persistence)
foo.close
end
end

View file

@ -0,0 +1,60 @@
require 'spec_helper'
describe "per-transition guards" do
let(:guardian) { GuardianMultiple.new }
it "allows the transition if the guard succeeds" do
expect { guardian.use_one_guard_that_succeeds! }.to_not raise_error
expect(guardian).to be_beta
end
it "stops the transition if the guard fails" do
expect { guardian.use_one_guard_that_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "allows the transition if all guards succeeds" do
expect { guardian.use_guards_that_succeed! }.to_not raise_error
expect(guardian).to be_beta
end
it "stops the transition if the first guard fails" do
expect { guardian.use_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "stops the transition if the second guard fails" do
expect { guardian.use_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
end
describe "event guards" do
let(:guardian) { GuardianMultiple.new }
it "allows the transition if the event guards succeed" do
expect { guardian.use_event_guards_that_succeed! }.to_not raise_error
expect(guardian).to be_beta
end
it "allows the transition if the event and transition guards succeed" do
expect { guardian.use_event_and_transition_guards_that_succeed! }.to_not raise_error
expect(guardian).to be_beta
end
it "stops the transition if the first event guard fails" do
expect { guardian.use_event_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "stops the transition if the second event guard fails" do
expect { guardian.use_event_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "stops the transition if the transition guard fails" do
expect { guardian.use_event_and_transition_guards_where_third_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
end

View file

@ -0,0 +1,15 @@
require 'spec_helper'
describe 'initial states' do
it 'should use the first state defined if no initial state is given' do
expect(NoInitialStateMultiple.new.aasm(:left).current_state).to eq(:read)
end
it 'should determine initial state from the Proc results' do
balance = InitialStateProcMultiple::RICH - 1
expect(InitialStateProcMultiple.new(balance).aasm(:left).current_state).to eq(:selling_bad_mortgages)
balance = InitialStateProcMultiple::RICH + 1
expect(InitialStateProcMultiple.new(balance).aasm(:left).current_state).to eq(:retired)
end
end

View file

@ -0,0 +1,202 @@
require 'spec_helper'
describe 'inspection for common cases' do
it 'should support the new DSL' do
# 1st state machine
expect(FooMultiple.aasm(:left)).to respond_to(:states)
expect(FooMultiple.aasm(:left).states.size).to eql 3
expect(FooMultiple.aasm(:left).states).to include(:open)
expect(FooMultiple.aasm(:left).states).to include(:closed)
expect(FooMultiple.aasm(:left).states).to include(:final)
expect(FooMultiple.aasm(:left)).to respond_to(:initial_state)
expect(FooMultiple.aasm(:left).initial_state).to eq(:open)
expect(FooMultiple.aasm(:left)).to respond_to(:events)
puts FooMultiple.aasm(:left).events.map(&:name).inspect
expect(FooMultiple.aasm(:left).events.size).to eql 2
expect(FooMultiple.aasm(:left).events).to include(:close)
expect(FooMultiple.aasm(:left).events).to include(:null)
# 2nd state machine
expect(FooMultiple.aasm(:right)).to respond_to(:states)
expect(FooMultiple.aasm(:right).states.size).to eql 3
expect(FooMultiple.aasm(:right).states).to include(:green)
expect(FooMultiple.aasm(:right).states).to include(:yellow)
expect(FooMultiple.aasm(:right).states).to include(:red)
expect(FooMultiple.aasm(:right)).to respond_to(:initial_state)
expect(FooMultiple.aasm(:right).initial_state).to eq(:green)
expect(FooMultiple.aasm(:right)).to respond_to(:events)
expect(FooMultiple.aasm(:right).events.size).to eql 3
expect(FooMultiple.aasm(:right).events).to include(:green)
expect(FooMultiple.aasm(:right).events).to include(:yellow)
expect(FooMultiple.aasm(:right).events).to include(:red)
end
context "instance level inspection" do
let(:foo) { FooMultiple.new }
let(:two) { FooTwoMultiple.new }
it "delivers all states" do
# 1st state machine
states = foo.aasm(:left).states
expect(states.size).to eql 3
expect(states).to include(:open)
expect(states).to include(:closed)
expect(states).to include(:final)
states = foo.aasm(:left).states(:permitted => true)
expect(states.size).to eql 1
expect(states).to include(:closed)
expect(states).not_to include(:open)
expect(states).not_to include(:final)
foo.close
expect(foo.aasm(:left).states(:permitted => true)).to be_empty
# 2nd state machine
states = foo.aasm(:right).states
expect(states.size).to eql 3
expect(states).to include(:green)
expect(states).to include(:yellow)
expect(states).to include(:red)
states = foo.aasm(:right).states(:permitted => true)
expect(states.size).to eql 1
expect(states).to include(:yellow)
expect(states).not_to include(:green)
expect(states).not_to include(:red)
foo.yellow
states = foo.aasm(:right).states(:permitted => true)
expect(states.size).to eql 2
expect(states).to include(:red)
expect(states).to include(:green)
expect(states).not_to include(:yellow)
end
it "delivers all states for subclasses" do
# 1st state machine
states = two.aasm(:left).states
expect(states.size).to eql 4
expect(states).to include(:open)
expect(states).to include(:closed)
expect(states).to include(:final)
expect(states).to include(:foo)
states = two.aasm(:left).states(:permitted => true)
expect(states.size).to eql 1
expect(states).to include(:closed)
expect(states).not_to include(:open)
two.close
expect(two.aasm(:left).states(:permitted => true)).to be_empty
# 2nd state machine
states = two.aasm(:right).states
expect(states.size).to eql 4
expect(states).to include(:green)
expect(states).to include(:yellow)
expect(states).to include(:red)
expect(states).to include(:bar)
states = two.aasm(:right).states(:permitted => true)
expect(states.size).to eql 1
expect(states).to include(:yellow)
expect(states).not_to include(:red)
expect(states).not_to include(:green)
expect(states).not_to include(:bar)
two.yellow
states = two.aasm(:right).states(:permitted => true)
expect(states.size).to eql 2
expect(states).to include(:green)
expect(states).to include(:red)
expect(states).not_to include(:yellow)
expect(states).not_to include(:bar)
end
it "delivers all events" do
# 1st state machine
events = foo.aasm(:left).events
expect(events.size).to eql 2
expect(events).to include(:close)
expect(events).to include(:null)
foo.close
expect(foo.aasm(:left).events).to be_empty
# 2nd state machine
events = foo.aasm(:right).events
expect(events.size).to eql 1
expect(events).to include(:yellow)
expect(events).not_to include(:green)
expect(events).not_to include(:red)
foo.yellow
events = foo.aasm(:right).events
expect(events.size).to eql 2
expect(events).to include(:green)
expect(events).to include(:red)
expect(events).not_to include(:yellow)
end
end
it 'should list states in the order they have been defined' do
expect(ConversationMultiple.aasm(:left).states).to eq([
:needs_attention, :read, :closed, :awaiting_response, :junk
])
end
end
describe "special cases" do
it "should support valid as state name" do
expect(ValidStateNameMultiple.aasm(:left).states).to include(:invalid)
expect(ValidStateNameMultiple.aasm(:left).states).to include(:valid)
argument = ValidStateNameMultiple.new
expect(argument.invalid?).to be_truthy
expect(argument.aasm(:left).current_state).to eq(:invalid)
argument.valid!
expect(argument.valid?).to be_truthy
expect(argument.aasm(:left).current_state).to eq(:valid)
end
end
describe 'aasm.states_for_select' do
it "should return a select friendly array of states" do
expect(FooMultiple.aasm(:left)).to respond_to(:states_for_select)
expect(FooMultiple.aasm(:left).states_for_select).to eq(
[['Open', 'open'], ['Closed', 'closed'], ['Final', 'final']]
)
end
end
describe 'aasm.from_states_for_state' do
it "should return all from states for a state" do
expect(ComplexExampleMultiple.aasm(:left)).to respond_to(:from_states_for_state)
froms = ComplexExampleMultiple.aasm(:left).from_states_for_state(:active)
[:pending, :passive, :suspended].each {|from| expect(froms).to include(from)}
end
it "should return from states for a state for a particular transition only" do
froms = ComplexExampleMultiple.aasm(:left).from_states_for_state(:active, :transition => :left_unsuspend)
[:suspended].each {|from| expect(froms).to include(from)}
end
end
describe 'permitted events' do
let(:foo) {FooMultiple.new}
it 'work' do
expect(foo.aasm(:left).events(:permitted => true)).to include(:close)
expect(foo.aasm(:left).events(:permitted => true)).not_to include(:null)
expect(foo.aasm(:right).events(:permitted => true)).to include(:yellow)
expect(foo.aasm(:right).events(:permitted => true)).not_to include(:green)
expect(foo.aasm(:right).events(:permitted => true)).not_to include(:red)
end
end