TIL: let! and before order is important
I’ve just come across this issue. It’s minor, but it tripped me up!
In RSpec, there are three methods I find myself using all the time:
before
- this is equivalent to thesetup
method present in many assertion-based test frameworks, and runs before each test.let
- this is a lazy-evaluated variable that will be made available to the context of each test - BUT it is undefined until called for the first time.let!
- this is the “evaluate right away” version oflet
. It will run before each example and already be available at that point.
Normally, in a feature or integration test that require data to be present, there will be some standard code:
RSpec.describe "My cool feature", type: :system do
let!(:widget) { FactoryBot.create(:widget) }
before { visit "/widgets" }
it "shows the widget" do
expect(page).to have_content widget.name
end
end
This is normally the pattern that I follow.
What I found is that, especially for let!
blocks where you want the data to be present
in the database before the route is visited, the order of the let!
and before
matters.
In the below example the test fails, as the let!
blocks actually run as they are evaluated, as in, after the before
block:
RSpec.describe "My cool feature", type: :system do
before { visit "/widgets" }
let!(:widget) { FactoryBot.create(:widget) }
it "shows the widget" do
expect(page).to have_content widget.name
end
end
Failure: Unable to to find content: "My widget"
There is an interesting issue lodged against rspec-core that has a bit more background as to why this happens, as well as some suggested workarounds. In my case, I just corrected the order of my before
and let!
calls to make sure the before
block came after the let!
s.