Set up visual regression testing in CI with Playwright. Capture screenshots, compare against baselines, and block PRs on visual changes.
## Task
Visual regression testing pipeline using Playwright screenshots.
## Requirements
- Framework: Playwright
- CI: GitHub Actions
- Storage: Git LFS or cloud (S3) for baseline screenshots
## Test Structure
```typescript
// Generate visual regression tests:
test.describe("Visual Regression", () => {
test("homepage matches baseline", async ({ page }) => {
await page.goto("/");
await page.waitForLoadState("networkidle");
await expect(page).toHaveScreenshot("homepage.png", {
maxDiffPixelRatio: 0.01, // 1% tolerance
threshold: 0.2, // per-pixel color threshold
animations: "disabled", // freeze CSS animations
});
});
test("homepage mobile", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto("/");
await expect(page).toHaveScreenshot("homepage-mobile.png");
});
// Dark mode variant
test("homepage dark mode", async ({ page }) => {
await page.emulateMedia({ colorScheme: "dark" });
await page.goto("/");
await expect(page).toHaveScreenshot("homepage-dark.png");
});
// Component-level screenshots
test("button variants", async ({ page }) => {
await page.goto("/storybook/button");
const button = page.getByTestId("primary-button");
await expect(button).toHaveScreenshot("button-primary.png");
});
});
```
## CI Workflow
```yaml
# On PR: capture screenshots, compare to main branch baselines
# If diff detected:
# 1. Post diff images as PR comment
# 2. Block merge until reviewed
# 3. Reviewer can approve visual changes (updates baselines)
```
## Implementation Notes
1. Baseline management: store in git (LFS) or S3 with version tagging
2. Update baselines: `npx playwright test --update-snapshots`
3. Cross-browser: test Chrome + Firefox (different rendering)
4. Fonts: install exact font versions in CI to prevent rendering differences
5. Flaky prevention: disable animations, wait for network idle, fixed viewport
6. Partial screenshots: capture specific components, not just full pagesNo gallery images yet.