Glossary · UI automation
Visual regression testing
Also called: visual testing, visual regression, visual regression tests, screenshot testing
Definition
Comparing screenshots of the UI against approved baseline images to catch unintended visual changes such as layout shifts, missing styles or overlaps.
Visual regression testing checks what the page looks like rather than what is in the DOM. The first run captures a baseline screenshot; later runs take a new screenshot and compare it pixel by pixel (or with a perceptual algorithm) against that baseline. Any difference above a threshold fails the test and produces a diff image highlighting what changed. It catches problems functional assertions miss, like a button pushed off screen by a CSS change.
Example (Playwright)
import { test, expect } from '@playwright/test';
test('dashboard looks right', async ({ page }) => {
await page.goto('/dashboard');
await expect(page).toHaveScreenshot('dashboard.png', {
fullPage: true,
mask: [page.getByTestId('last-updated')],
maxDiffPixels: 100,
});
});
test('pricing card', async ({ page }) => {
await page.goto('/pricing');
await expect(page.getByTestId('pro-plan')).toHaveScreenshot();
});
The first run fails because no baseline exists and writes one. After a deliberate design change, regenerate baselines with:
npx playwright test --update-snapshots
toHaveScreenshot is a web-first assertion: it retakes the screenshot until two consecutive captures match, which avoids comparing a frame from mid-animation.
Making it stable
- Same environment for baselines and runs. Fonts and anti-aliasing differ between operating systems, which is why Playwright stores baselines per browser and platform. Generate them in the same Docker image CI uses.
- Mask dynamic content. Timestamps, avatars, ads and charts with live data will always differ.
- Freeze time and data. Use fixed test data and, where needed, a mocked clock.
- Disable animations. Playwright disables CSS animations for screenshots by default.
- Prefer components to full pages. A screenshot of one card fails for one reason; a full page fails for twenty.
Common mistakes
- Approving diffs without looking. Updating baselines in bulk turns the suite into a rubber stamp.
- Zero tolerance everywhere. Tiny rendering differences cause noise. Set a small threshold, but not so large it hides real regressions.
- Using it instead of functional tests. A screenshot can show the total is in the right place, not that it is the right number.