Use when implementing UI components, design systems, or responsive layouts - verifies visual correctness through screenshot comparison and DevTools verification; prevents shipping broken UI
Captures screenshots of UI components and compares them against baselines to detect visual regressions. Triggers when implementing UI components, design systems, or responsive layouts to verify visual correctness before shipping.
/plugin marketplace add samjhecht/wrangler/plugin install wrangler@samjhecht-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
example.tsMANDATORY: When using this skill, announce it at the start with:
š§ Using Skill: frontend-visual-regression-testing | [brief purpose based on context]
Example:
š§ Using Skill: frontend-visual-regression-testing | [Provide context-specific example of what you're doing]
This creates an audit trail showing which skills were applied during the session.
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 test-driven-development 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.
Master defensive Bash programming techniques for production-grade scripts. Use when writing robust shell scripts, CI/CD pipelines, or system utilities requiring fault tolerance and safety.