Day 11: Visual Regression Testing — Catch UI Bugs Pixel by Pixel
This is Day 11 of the 21-Day Playwright with TypeScript Challenge. One lesson per day. Zero to production-ready in 3 weeks.
🎭 Want to master this with real projects? Join the Playwright Automation Mastery course at The Testing Academy.
toHaveScreenshot() compares current page to baseline snapshot. Any pixel difference = test failure. Catches CSS regressions, layout shifts, font changes that functional tests miss.
Contents
Basic Visual Test
test('homepage visual check', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png');
});
// First run: creates baseline in tests/__snapshots__/
// Subsequent runs: compares to baseline
// Fails if pixels differ beyond threshold
Element-Level Screenshots
test('header visual check', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('banner')).toHaveScreenshot('header.png');
});
test('product card visual', async ({ page }) => {
await page.goto('/products');
const card = page.getByTestId('product-card').first();
await expect(card).toHaveScreenshot('product-card.png');
});
🚀 Level Up Your Playwright
From locators to CI pipelines — build a production-grade Playwright + TypeScript framework step by step.
Masking Dynamic Content
test('dashboard with masked dynamic areas', async ({ page }) => {
await page.goto('/dashboard');
await expect(page).toHaveScreenshot('dashboard.png', {
mask: [
page.getByTestId('timestamp'),
page.getByTestId('live-chart'),
page.getByTestId('notification-count'),
],
maxDiffPixelRatio: 0.01, // Allow 1% pixel diff
});
});
Updating Baselines
# After intentional UI change, update snapshots
npx playwright test --update-snapshots
Tomorrow (Day 12): Parallel execution and sharding for speed.
🎓 Master Playwright End to End
Join hundreds of SDETs building real automation frameworks. Lifetime access, hands-on projects, and a job-ready portfolio.
