let! & before execution order in RSpec
When updating a spec the other day, I was running into an issue where a variable I was defining with let!
was not being found. It turns out the before
actually needed the variable defined with let!
, but it hadn’t been instantiated yet. Which led me to question what is the order of execution between let!
and before
? Turns out:
let!
andbefore
(within the same block) are executed in order of definition. So whichever is defined first will be executed first.
So for example
RSpec.describe do
let!(:variable_name) { puts '-- let! block' }
before { puts "-- before block" }
it { expect(true).to be(true) }
end
Will result in:
-- let! block
-- before block
Define the let after the before:
before { puts "-- before block" }
let!(:variable_name) { puts '-- let! block' }
And you’ll get
-- before block
-- let! block
What about nested blocks?
The ordering only matters for definitions in the same block. The more nested a block is, the later it will be executed.
RSpec.describe do
context 'nested context' do
let!(:nested_variable_name) { puts '-- nested let! block' }
before { puts "-- nested before block" }
it { expect(true).to be(true) }
end
before { puts "-- before block" }
let!(:variable_name) { puts '-- let! block' }
end
Results in:
-- before block
-- let! block
-- nested let! block
-- nested before block
Even though the higher level before
and let!
are defined after, they are executed later.
Conclusion
This is all fairly expected, but is just a reminder that the ordering of before
and let!
does matter.