I am using the following versions:
ruby 2.5.5
rails 5.2.3
state_machines-activerecord 0.6.0
I have a model Foo that has a state machine on it:
class Foo < ApplicationRecord
def post_activate
puts "hello from sunny post_activate"
end
state_machine :state, initial: :initial do
state :active
after_transition any => :active, :do => :post_activate
event :activate do
transition initial: :active
end
end
end
I'm trying to write an rspec test to ensure post_activate
gets called after the transition to state :active.
I can test ok from the Rails console:
2.5.5 :001 > thinger = Foo.new
=> #<Foo id: nil, state: "initial", created_at: nil, updated_at: nil>
2.5.5 :002 > thinger.activate
(0.1ms) begin transaction
Foo Create (0.4ms) INSERT INTO "foos" ("state", "created_at", "updated_at") VALUES (?, ?, ?) [["state", "active"], ["created_at", "2019-06-28 21:35:22.555917"], ["updated_at", "2019-06-28 21:35:22.555917"]]
hello from sunny post_activate
(0.7ms) commit transaction
=> true
However, when I run my test:
describe 'Foo' do
it 'should fire post_activate' do
foo = Foo.new
expect(foo).to receive(:post_activate)
foo.activate
end
end
I get the following error:
1) Foo should fire post_activate
Failure/Error: foo.activate
ArgumentError:
Wrong number of arguments. Expected 0, got 1.
Interestingly, another test runs correctly with no errors:
it 'should change the state' do
foo = Foo.new
expect{
foo.activate
}.to change {
foo.state
}.from('initial').to('active')
end
This test passes and prints my debug message.
I tried putting a parameter into the post_activate
definition:
def post_activate(arg)
puts arg
puts "hello from sunny post_activate"
end
Now the test passes - and the puts statement reveals that the object passed in is a StateMachines::Transition
#<StateMachines::Transition:0x00007fd5d3534228>
hello from sunny post_activate
I'm not sure how this works - I know how to make a parameter optional, but I don't know how to optionally pass an argument.
In any case - the test passes if I add a parameter to my method definition. But I don't want to add a parameter I'm not using just to get my specs to pass. How do I resolve this?
RSpec verifying proxy in validate_arguments!
getting call for post_activate
with current transition. You can see it if you add something like byebug
to your Gemfile, and add same byebug conditionally into validate_arguments!
of Rspec:
@method_reference.with_signature do |signature|
verifier = Support::StrictSignatureVerifier.new(signature, actual_args)
byebug unless verifier.valid?
raise ArgumentError, verifier.error_message unless verifier.valid?
That will give you access to actual_args:
(byebug) actual_args
[#<StateMachines::Transition ...]
So to fix your problem, you just need to add omitted parameter to your callback (as you clearly already figure out):
def post_activate(_)
And to be sure why underscore used that way, take a look at Ruby Style Guide.