| name | Visual Regression |
| description | Screenshot comparison testing for UI changes. Use when: detecting unintended UI changes, validating design consistency, or automating visual QA. |
Visual Regression
Automated screenshot comparison testing.
Setup
import { defineConfig } from '@playwright/test';
export default defineConfig({
expect: {
toHaveScreenshot: {
maxDiffPixels: 1000,
threshold: 0.25,
},
},
});
Basic Test
test('login page visual', async ({ page }) => {
await page.goto('/login');
await page.waitForLoadState('networkidle');
await page.emulateMedia({ reducedMotion: 'reduce' });
await expect(page).toHaveScreenshot('login-page.png');
});
Component Testing
test('button component states', async ({ mount }) => {
const button = await mount(<Button>Click me</Button>);
await expect(button).toHaveScreenshot('button-default.png');
await button.hover();
await expect(button).toHaveScreenshot('button-hover.png');
await button.click({ force: true });
await button.isDisabled();
await expect(button).toHaveScreenshot('button-disabled.png');
});
CI Integration
- name: Visual Tests
run: npx playwright test --project=visual
- name: Upload baseline
if: failure()
run: |
git checkout main -- tests/snapshots/
npx playwright test --project=visual
# Review and commit new baselines
Update Baselines
npx playwright test --update-snapshots
npx playwright test --update-snapshots login.spec.ts
Best Practices
- Isolate — test one component per screenshot
- Stable content — mock dynamic content (dates, usernames)
- Disable animations — use
reducedMotion
- Consistent viewport — same browser size always
- Review false positives — acceptable differences (fonts, antialiasing)
For Mansoni
Critical pages for visual regression:
- Landing page
- Chat interface
- Settings panels
- Modals and dialogs