Visual Regression Testing: The Most Important Test You're Not Running | How To Test Frontend
Visual Regression Testing: The Most Important Test You're Not Running<br>On this page<br>On this page
You can have 100% test coverage, all your tests passing and functionality wise, it might work fine - but it might look completely broken.
Typical unit, integration and end-to-end (E2E) tests will test functionality - what your app can do - such as rendering the correct text, interactions when you click a button, firing off API requests. But none of this checks how your app or components actually appear to users .
This is where visual regression testing can help you. It takes visual screenshots of your page or components, and compares them against a baseline image to check that nothing changed.
So if you update an SVG and change it from width="50" to width="100", it will catch it if this icon was used on another section of the site that you didn't think to manually check.
If they match: all good! If something changed visually, then it will be a test failure on your CI/CD workflow.
With tools like Percy , a visual change will normally be raised as a failure until you log in to Percy and approve the changes
Note: I am going to sound like I am promoting Percy. I have no affiliation with them. They just,<br>in my opinion, have the best UI and tools for visual regression testing!
With the rise of AI-generated code changes, visual regression tests are going to become even more crucial so I really think more companies should get on board and start using them.
Here are a couple of examples. In Percy I am using the view where it shows the baseline version on the left, and my changes on the right.
In this one I changed the header area, so it spotted the difference and made me approve the changes:
And in this one I changed the list of articles on the left sidebar:
You can see in these screenshots I approved the changes - they were intentional. Of course the value in visual regression tests is when you accidentally change something without realising.
Unit tests check behaviour
Integration tests and E2E tests check behaviour & how it all works<br>together
API Contract tests check response types/shapess
Visual regression tests check appearance
Why is visual regression testing important?
When you write tests (unit, integration or E2E) you are normally testing things like:
input arguments (or props on a component)
returned values (or what a component renders)
and side effects like a fetch() call or window.localStorage update
You could test CSS classnames (like expect(btn).toHaveClass('btn-primary')) but this is generally a code smell when it comes to testing as you're testing implementation details rather than user-facing behaviour.
Even if all your class names are correct, the actual visual appearance could still be broken due to things like CSS changes, CSS not loading correctly, specificity issues, or external stylesheets interfering.
Visual regression tests are the solution to this as it really does test what the user will see, and is not testing implementation details. (It won't matter if you're using Tailwind, BEM, styled-components or if you switch it around - all it cares about is how it renders).
How does it work?
There are a few ways to set it up, but broadly speaking the tools that you use for visual regression tests:
render your component or page in a real browser, in a headless mode (this can run on your CI/CD platform, such as GitHub Actions)
Quite often this will just be in your regular E2E tests (like Playwright or Cypress), and you pass the page object to a function that will deal with taking the screenshot
In Vitest Browser Mode it has built in screenshot testing.
This gets compared to your baseline snapshot.
If any changes (and you're happy with those changes): you approve it.
If you did not expect changes then you have to change your code and push another commit
if there were no changes, then it will auto approve
Once you merge your PR into your default branch (e.g. main), then it will regenerate the screenshots and mark those new ones as the baseline ones
What gets tested and what kinds of bugs will it catch?
It can catch anything that might happen visually.
I would say the main things it catches are:
You changed a component in one place, without realising the other places that component was used
CSS changes (changes you made to your CSS, or other CSS with more specificity etc)
Layout changes - overlapping content, position changes, etc
Responsive issues (you can set them to take screenshots in different screen sizes)
Different browser renders (take screenshots in Chrome, Firefox, Safari etc)
Font or image loading issues (as they'll start showing up as a missing image)
It is also good at catching subtle bugs.
I remember years ago (I've been using visual regression tests since around 2018) updating one icon SVG which I believed was a super safe change, about to push to...