0

I have a class like this

class Job
  include AASM

  aasm do
    state :created, initial: true
    state :processing, :notifying, :finished, :error

    event :process do
      before do
        # do some undesired stuffs for test
      end
      transitions from: :created, to: :processing
    end

    event :notify do
      transitions from: :processing, to: :notifying
    end

    event :finish do
      before do
        # do more undesired stuffs for test
      end
      transitions from: [:processing, :notifying], to: :finished
    end

    event :error do
      transitions to: :error
    end
  end

  def notify?
    Date.today.saturday?
  end

  def run!
    process!
    notify! if notify?
    finish!
  rescue
    error!
  end
end

I want to create a test to verify if run! is following the workflow as expected, but in my transitions I have some callbacks that I don't want to trigger in this tests.

before do
  allow(job).to receive(:notify?).and_return(false)
  # do some magick to disable the callbacks
end

it do
  job.run!
  expect(job).to have_received(:process!)
  expect(job).to have_received(:finish!)
  expect(job).not_to have_received(:notify!)
  expect(job).not_to have_received(:error!)
end

Is there some way to disable the AASM callbacks in a rspec test or the only alternative is mock everything inside the callbacks?

PS
My actual classes are much more complex than those examples.

1 Answers1

0

You can wrap the callback logic in a method and stub those method calls. Eg.

    event :process do
      before do
        wrapped_method_one
        wrapped_method_two
      end
      transitions from: :created, to: :processing
    end

RSpec:

before { allow(job).to receive(:wrapped_method_one) } 
before { allow(job).to receive(:wrapped_method_two) } 
fylooi
  • 3,840
  • 14
  • 24
  • Thanks for this answer. I have the same question, but outside of the context of testing. I'm writing scripts or rake tasks. And sometimes you want to be able to put models in a certain state without firing the callbacks. It doesn't seem like this is currently supported by the library. – Marco Sep 17 '19 at 21:28
  • @Marco If your models are ActiveRecord, you can just define a new model with any name, use `self.table_name=` to point it to the same table and update the table's state as you wish without going through AASM. – fylooi Sep 20 '19 at 05:09