Snaphot tests can be very helpful when refactoring the logic behind views
Snaphot testing, rightly, has a bad reputation at Dragon Drop. The way it works is - you generate a snapshot of the output you have; and then you test that you still have that output.
When you make a change that you want, you save the new snapshot.
It’s a great idea in theory, but in practice, we’ve found that the temptation to just save the new snapshot every time is too great, and bugs get missed. We’re testing that what we’ve got is what we’ve got.
There is, however, one good use case that we put into practice this week.
We had a very important page; we wanted to refactor some of the way it was constructed on the Ruby side, but we can’t risk changing what it outputs.
To have a ‘green test at our back’, we used rspec-snapshot to ensure we weren’t changing the resulting HTML as we were tidying up the code.
How to do it
The setup was simple, we added the gem, and then wrote some snapshot specs with various output contexts:
it "matches the header section snapshot" do
expect(rendered_component).to match_snapshot("project/show/sections/header")
end
context "with high_touch project" do
let(:project) { create(:project, id: 1, lead:, high_touch: true) }
it "matches the header section snapshot" do
expect(rendered_component).to match_snapshot("project/show/sections/header/with_high_touch")
end
end
This is all we need to do. The first time we run this spec, the gem will generate an HTML snapshot relative to this directory.
Now, as we make changes to the logic, we can keep running this test and check we haven’t changed the output.
Gotchas
There are a couple of annoying gotchas to watch out for.
- if you depend on factory bot, you’ll need to fix the id’s of various records in your spec, otherwise the Rails-generated ids on form fields will change every time you generate your snapshot:
let(:project) { create(:project, id: 1) }
- Random seeds in factories cause problems.
We were using Faker::Name
to generate names for some of our records, and we had to change these to be fixed names.
- They’re very brittle with the full test suite
This again, comes down to FactoryBot. If you have a unique attribute, like an email, you’re likely incrementing it in your factory:
sequence(:email) {|n| "email_#{n}@example.com" }
which can change depending on the test order run. This is fixable by being explicit about unique values on your tests that are snapshotted.
None of these Gotchas are too much of a problem, as we don’t intend to keep the snapshot specs around once our refactors are complete.
Conclusion
Snapshot tests can be a great safety layer when refactoring views, partials or ViewComponents. They’re still a terrible first choice for specs in general.
— Adam Dawkins
Who are Dragon Drop?
Dragon Drop is a specialist web and app development agency. The team has extensive full-stack technical credentials and a strong focus on user experience.
The Dragon Drop founding team have over 40 years of web development and project experience. They have managed or developed over 100 significant ecommerce and web projects during their careers, including implementations for major UK high street retailers, financial services companies and government agencies.
Their approach to innovative solutions stems from perspectives gained as retailer, software supplier and web agency.