let! & before execution order in RSpec

Ryan von Kunes Newton
2 min readOct 25, 2023

--

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! and before (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.

--

--

No responses yet