Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Functional tests verify that buttons work. Visual regression tests verify that the page looks correct. A CSS change that accidentally shifts a checkout button 10 pixels to the right, hides text under a nav bar, or changes the font size in a critical CTA might pass all functional tests but ship as a visual defect. Visual regression testing works by taking a screenshot of each page state, comparing it pixel-by-pixel to a baseline (the approved version), and failing when the diff exceeds a threshold. It catches the class of bugs that only a human eye would catch — but automated, so it runs on every commit.
Playwright's toHaveScreenshot() captures a pixel-accurate baseline on the first run and diffs subsequent runs against it, failing when the changed area exceeds a configurable threshold. Functional tests verify behavior; visual regression tests verify appearance — a CSS regression that shifts a checkout button off-screen will pass all functional assertions while shipping a broken UI to users. Running snapshot comparisons in CI catches an entire class of bugs that no amount of selector-based testing can reach.
maxDiffPixels: 0 and re-run on a page that has a timestamp, animation, or random element. Watch it fail. Then use page.evaluate(() => document.querySelector('.timestamp').remove()) before the screenshot to mask the dynamic content. Re-run — it should pass.import { test, expect } from '@playwright/test';
// Playwright's toHaveScreenshot() compares against stored baselines.
// First run: baselines are created. Subsequent runs: compared.
// Update baselines: npx playwright test --update-snapshots
test('homepage visual regression', async ({ page }) => {
await page.goto('/');
// Full-page screenshot comparison
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixels: 50, // allow up to 50 pixels of diff
threshold: 0.2, // 0-1 scale; 0.2 = 20% pixel brightness diff allowed
fullPage: true,
});
});
test('checkout button is visible and styled correctly', async ({ page }) => {
await page.goto('/checkout');
// Component-level screenshot (just one element)
const checkoutBtn = page.getByRole('button', { name: 'Place Order' });
await expect(checkoutBtn).toHaveScreenshot('checkout-btn.png');
});
test('error state visual — form validation', async ({ page }) => {
await page.goto('/contact');
await page.getByRole('button', { name: 'Submit' }).click(); // submit empty form
// Capture the error state
await expect(page.locator('form')).toHaveScreenshot('contact-form-errors.png', {
maxDiffPixels: 0, // zero tolerance for error state — must match exactly
});
});
// CI tip: only run visual tests on specific environments to avoid false positives
// from font rendering differences between OS:
// npx playwright test --project=chromium (consistent rendering)node main.js