skills/frontend/visual-regression-testing/SKILL.md
Use when implementing UI components, design systems, or responsive layouts - verifies visual correctness through screenshot comparison and DevTools verification; prevents shipping broken UI
npx skillsauth add bacchus-labs/wrangler visual-regression-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Visual regression testing captures screenshots of UI components/pages and compares them against baseline images to detect unintended visual changes.
When to use this skill:
NO UI CHANGES WITHOUT VISUAL VERIFICATION
If you changed UI code (HTML, CSS, JSX, templates):
Visual regression testing integrates with TDD through TWO sequential cycles:
RED Phase:
test('checkout form renders with required fields', async ({ mount }) => {
const component = await mount('<checkout-form></checkout-form>');
// Test functionality (TDD RED - this will fail)
await expect(component.locator('[name="cardNumber"]')).toBeVisible();
await expect(component.locator('[name="expiry"]')).toBeVisible();
await expect(component.locator('[name="cvc"]')).toBeVisible();
});
Run test: FAILS (component doesn't exist)
GREEN Phase:
// Implement checkout-form component
// Add cardNumber, expiry, cvc fields
Run test: PASSES (component renders fields)
REFACTOR Phase: Improve component structure, styling, accessibility
After component functionally works, add visual verification:
test('checkout form visual appearance', async ({ mount, page }) => {
await mount('<checkout-form></checkout-form>');
// Visual regression test
await expect(page.locator('.checkout-form'))
.toHaveScreenshot('checkout-form.png');
});
First run (Baseline Generation):
RED Phase (Visual Regression): After baseline exists, make CSS change:
/* Change button color from blue to red */
.submit-button { background: red; }
Run test: FAILS (screenshot doesn't match baseline) Review diff: Is change intentional?
GREEN Phase (Update Baseline if Intentional): If red button is intentional:
npm test -- --update-snapshots
New baseline committed Run test: PASSES
If red button is NOT intentional (regression):
/* Revert change */
.submit-button { background: blue; }
Run test: PASSES
Integration:
Cross-reference: See practicing-tdd skill for core RED-GREEN-REFACTOR principles.
IF baseline exists (modifying existing UI):
IF no baseline (new UI):
Write tests first (TDD):
// Test that component renders
test('checkout form renders correctly', async ({ page }) => {
await mount('<checkout-form></checkout-form>');
// Take screenshot of component
await expect(page.locator('[data-testid="checkout-form"]'))
.toHaveScreenshot('checkout-form.png');
});
Implement component (GREEN phase)
Prefer element-level over full-page:
// ✅ GOOD: Element-level (less noise)
await expect(page.locator('.checkout-form'))
.toHaveScreenshot('checkout-form.png');
// ❌ BAD: Full page (too much noise)
await expect(page).toHaveScreenshot('entire-page.png');
BEFORE claiming UI works:
Open DevTools Console:
Verify NO errors:
✅ GOOD: Console is empty (or only expected logs)
❌ BAD: Red errors visible
❌ BAD: Yellow warnings visible (unless documented)
Take Console Screenshot:
Check Network Tab:
Test Responsive Breakpoints:
IF baseline exists:
// Test runs, Playwright compares screenshots
// IF different: Test fails with diff image
Review diff image:
Decision tree:
Are differences intentional?
├─ YES → Update baseline, document why
└─ NO → Fix regression, re-run test
IF no baseline:
Baseline files:
tests/
screenshots/
checkout-form.png ← Baseline
checkout-form-diff.png ← Diff (if different)
checkout-form-actual.png ← Actual (if different)
When to update baseline:
Updating baseline:
# Review diff first!
# If intentional, update baseline:
npm test -- --update-snapshots
# Or Playwright specific:
npx playwright test --update-snapshots
test('visual regression', async ({ page }) => {
await page.goto('/checkout');
// Element-level screenshot
await expect(page.locator('.checkout-form'))
.toHaveScreenshot('checkout-form.png', {
maxDiffPixels: 100, // Allow minor differences
});
});
test('visual regression', async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000/checkout');
const element = await page.$('.checkout-form');
await element.screenshot({ path: 'checkout-form.png' });
// Compare manually or use Percy/Chromatic
await browser.close();
});
YES (visual tests appropriate):
NO (use other test types):
// playwright.config.ts
export default defineConfig({
expect: {
toHaveScreenshot: {
maxDiffPixels: 100, // Allow minor rendering differences
threshold: 0.2, // 20% threshold for pixel differences
animations: 'disabled', // Disable animations for stability
},
},
});
BEFORE claiming UI work complete:
If ANY checkbox unchecked: UI work is NOT complete.
When claiming UI work complete, provide:
Screenshot evidence:
Screenshot: checkout-form.png (baseline)
[Attach screenshot]
Changes: Intentional (updated button styling)
Baseline updated: YES
DevTools Console evidence:
Console verification:
[Screenshot showing empty console]
Errors: 0
Warnings: 0
Network evidence (if API calls):
Network verification:
[Screenshot showing successful requests]
Expected requests: ✓ GET /api/products
Failed requests: 0
If you catch yourself:
THEN:
Combines with:
| Rationalization | Counter | |----------------|---------| | "I can see it looks good" | Your eyes aren't regression tests. Take screenshot. | | "It's a small change" | Small changes cause visual regressions. Screenshot required. | | "I'll check it in the browser" | Browser check ≠ automated verification. Take screenshot. | | "Console errors don't affect appearance" | Errors indicate bugs. Fix before claiming complete. | | "Full page screenshot is easier" | Element screenshots catch actual changes. Be specific. |
Agent: "I'm implementing a checkout form component."
[Uses frontend-visual-regression-testing skill]
1. Write test expecting checkout form renders
2. Take screenshot of component → baseline
3. Run test → PASS (baseline generated)
4. Refactor CSS for better spacing
5. Run test → FAIL (screenshot different)
6. Review diff → Intentional (better spacing)
7. Update baseline
8. Open DevTools console → 0 errors
9. Take console screenshot
10. Test responsive breakpoints → All look correct
11. Provide evidence in completion message:
- checkout-form.png (baseline)
- Console screenshot (0 errors)
- Responsive screenshots (mobile/tablet/desktop)
"Checkout form complete. Visual regression test passing.
Console clean. Responsive breakpoints verified."
Remember: NO UI CHANGES WITHOUT VISUAL VERIFICATION. Screenshots are evidence, not optional.
tools
Use when creating technical specifications for features, systems, or architectural designs. Creates comprehensive specification documents using the Wrangler MCP issue management system with proper structure and completeness checks.
testing
Creates and refines agent skills using TDD methodology with pressure testing and rationalization detection. Use when creating new skills, editing existing skills, testing skills with pressure scenarios, or verifying skills work before deployment.
tools
Use when design is complete and you need detailed implementation tasks - creates tracked MCP issues with exact file paths, complete code examples, and verification steps. Optional reference plan file for architecture overview.
development
Validates governance file completeness, format compliance, and metric accuracy. Use when auditing governance health, after bulk changes, or ensuring documentation integrity.