From 9e9f3d0a766484a65b0bc7182675a893724de5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20B=C3=B6ttger?= Date: Fri, 30 Oct 2015 23:47:13 +1300 Subject: [PATCH] support RSpec match transition_from --- CHANGELOG.md | 4 ++++ README.md | 33 ++++++++++++------------------- lib/aasm/rspec.rb | 5 +++++ lib/aasm/rspec/transition_from.rb | 32 ++++++++++++++++++++++++++++++ spec/spec_helper.rb | 1 + spec/unit/rspec_matcher_spec.rb | 21 ++++++++++++++++++++ 6 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 lib/aasm/rspec.rb create mode 100644 lib/aasm/rspec/transition_from.rb create mode 100644 spec/unit/rspec_matcher_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index a310500..a776238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## unreleased + + * add RSpec matcher `transition_from` (see [issue #178](https://github.com/aasm/aasm/issues/178) for details, thanks to [@thomasstephane](https://github.com/thomasstephane)) + ## 4.4.1 * add support for rejecting certain events on inspection (see [issue #272](https://github.com/aasm/aasm/issues/272) for details, thanks to [@dubroe](https://github.com/dubroe)) diff --git a/README.md b/README.md index aa08d70..2f9f13a 100644 --- a/README.md +++ b/README.md @@ -723,28 +723,21 @@ Job.aasm.states_for_select ### Testing -AASM provides matchers for [RSpec](http://rspec.info). +AASM provides some matchers for [RSpec](http://rspec.info). Add `require 'aasm/rspec'` to your `spec_helper.rb` file and use them like this - job = Job.new - job.should have_state :sleeping - job.should allow_transition_to :running - job.should allow_event :run - job.should allow_event :run! - job.should_not allow_event :clean - job.should_not allow_event :clean! - - simple = SimpleMultipleExample.new - simple.should have_state :standing, :on => :move - simple.should allow_transition_to :walking, :on => :move - simple.should allow_event :run - simple.should allow_event :run! - simple.should have_state :sleeping, :on => :work - simple.should allow_transition_to :processing, :on => :work - simple.should allow_event :start - simple.should allow_event :start! - simple.should_not allow_event :stop - simple.should_not allow_event :stop! +```ruby +# classes with only the default state machine +job = Job.new +expect(job).to transition_from(:sleeping).to(:running).on_event(:run) +expect(job).not_to transition_from(:sleeping).to(:cleaning).on_event(:run) +# classes with multiple state machine +multiple = SimpleMultipleExample.new +expect(multiple).to transition_from(:standing).to(:walking).on_event(:walk).on(:move) +expect(multiple).to_not transition_from(:standing).to(:running).on_event(:walk).on(:move) +expect(multiple).to transition_from(:sleeping).to(:processing).on_event(:start).on(:work) +expect(multiple).to_not transition_from(:sleeping).to(:sleeping).on_event(:start).on(:work) +``` ## Installation ## diff --git a/lib/aasm/rspec.rb b/lib/aasm/rspec.rb new file mode 100644 index 0000000..fd2e846 --- /dev/null +++ b/lib/aasm/rspec.rb @@ -0,0 +1,5 @@ +# relative-require all rspec files +Dir[File.dirname(__FILE__) + '/rspec/*.rb'].each do |file| + require 'aasm/rspec/' + File.basename(file, File.extname(file)) +end + diff --git a/lib/aasm/rspec/transition_from.rb b/lib/aasm/rspec/transition_from.rb new file mode 100644 index 0000000..44c2f16 --- /dev/null +++ b/lib/aasm/rspec/transition_from.rb @@ -0,0 +1,32 @@ +RSpec::Matchers.define :transition_from do |from_state| + match do |obj| + @state_machine_name ||= :default + obj.aasm(@state_machine_name).current_state = from_state.to_sym + # expect(obj).to receive(:broadcast_event).with(@event.to_s, obj, from_state, @to_state) + obj.send(@event) && obj.aasm(@state_machine_name).current_state == @to_state.to_sym + end + + chain :on do |state_machine_name| + @state_machine_name = state_machine_name + end + + chain :to do |state| + @to_state = state + end + + chain :on_event do |event| + @event = event + end + + description do + "transition state to :#{@to_state} from :#{expected} on event :#{@event} (on :#{@state_machine_name})" + end + + failure_message do |obj| + "expected that :#{obj.aasm(@state_machine_name).current_state} would be :#{@to_state} (on :#{@state_machine_name})" + end + + failure_message_when_negated do |obj| + "expected that :#{obj.aasm(@state_machine_name).current_state} would not be :#{@to_state} (on :#{@state_machine_name})" + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f812a2c..5c3c3e2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))) require 'aasm' require 'rspec' +require 'aasm/rspec' # require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying' # require 'ruby-debug/completion' diff --git a/spec/unit/rspec_matcher_spec.rb b/spec/unit/rspec_matcher_spec.rb new file mode 100644 index 0000000..3ac3e3e --- /dev/null +++ b/spec/unit/rspec_matcher_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe 'state machine' do + let(:simple) { SimpleExample.new } + let(:multiple) { SimpleMultipleExample.new } + + describe 'transition_from' do + it "works for simple state machines" do + expect(simple).to transition_from(:initialised).to(:filled_out).on_event(:fill_out) + expect(simple).to_not transition_from(:initialised).to(:authorised).on_event(:fill_out) + end + + it "works for multiple state machines" do + expect(multiple).to transition_from(:standing).to(:walking).on_event(:walk).on(:move) + expect(multiple).to_not transition_from(:standing).to(:running).on_event(:walk).on(:move) + + expect(multiple).to transition_from(:sleeping).to(:processing).on_event(:start).on(:work) + expect(multiple).to_not transition_from(:sleeping).to(:sleeping).on_event(:start).on(:work) + end + end +end