Answer
Visual Regression Testing in Playwright
Visual regression testing catches unexpected visual changes by comparing screenshots to baseline images.
Basic Screenshot Comparison
TypeScript
import { test, expect } from '@playwright/test';
test('homepage looks correct', async ({ page }) => {
await page.goto('/');
// Compare full page to baseline
await expect(page).toHaveScreenshot('homepage.png');
});
test('button styles are correct', async ({ page }) => {
await page.goto('/design-system');
// Compare a specific element
await expect(page.locator('.button-group')).toHaveScreenshot('buttons.png');
});
First Run — Creates Baseline
Bash
# First run generates baseline images in __snapshots__/
npx playwright test
Subsequent Runs — Compare to Baseline
Any pixel difference above threshold fails the test:
CODE
Error: Screenshot comparison failed:
Expected: homepage.png
Received: homepage-actual.png
Diff: 234 pixels changed (0.3%)
Update Baselines
Bash
# Regenerate all baselines
npx playwright test --update-snapshots
Configuration Options
TypeScript
// playwright.config.ts
export default defineConfig({
expect: {
toHaveScreenshot: {
maxDiffPixels: 100, // Allow up to 100 different pixels
maxDiffPixelRatio: 0.01, // Allow up to 1% pixel difference
threshold: 0.2, // Color distance threshold (0-1)
animations: 'disabled', // Disable CSS animations before screenshot
},
},
});
Masking Dynamic Areas
TypeScript
// Ignore areas that change (timestamps, ads, etc.)
await expect(page).toHaveScreenshot('dashboard.png', {
mask: [
page.locator('.timestamp'),
page.locator('.live-count'),
page.locator('#ad-banner'),
],
});
Full Visual Test Suite
TypeScript
import { test, expect } from '@playwright/test';
const pages = [
{ name: 'home', path: '/' },
{ name: 'login', path: '/login' },
{ name: 'dashboard', path: '/dashboard' },
{ name: 'products', path: '/products' },
];
for (const { name, path } of pages) {
test(`${name} page visual regression`, async ({ page }) => {
await page.goto(path);
// Wait for animations to settle
await page.waitForLoadState('networkidle');
await expect(page).toHaveScreenshot(`${name}.png`, {
fullPage: true,
animations: 'disabled',
});
});
}
Folder Structure for Snapshots
CODE
tests/
├── visual/
│ └── homepage.spec.ts
└── __snapshots__/
└── visual/
├── homepage.spec.ts-snapshots/
│ ├── homepage-chromium-darwin.png # Platform-specific baselines
│ ├── homepage-firefox-darwin.png
│ └── homepage-webkit-darwin.png
Important: Visual baselines are OS and browser-specific. CI and local machines often differ — create and update baselines in CI to avoid false failures.
