playwright-visual-testing

Diagnose and fix flaky visual diffs in Playwright archive-replay captures by pinning run-to-run page variation.

21|1|Updated Jul 22, 2026
One-click install
npx skills add https://github.com/uiverify/uiverify --skill playwright-visual-testing-uiverify
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: playwright-visual-testing
Source: https://github.com/uiverify/uiverify/tree/main/packages/skills/skills/playwright-visual-testing
Command: npx skills add https://github.com/uiverify/uiverify --skill playwright-visual-testing-uiverify

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill requires @uiverify/playwright.

What problem does it solve? Visual tests that drive a real page with @uiverify/playwright keep coming back "changed" without any real change, because the archive bakes in whatever the page was at capture time — random A/B variants, live API data, the clock, third-party widgets, lazy content, and animations all inject run-to-run variation that shows up as flaky diffs. ## Core Features & Use Cases - Symptom-to-lever diagnosis: Maps each flaky diff pattern (whole-page reflow, content drift, random element swaps, canvas noise) to its cause class and the exact fix recipe. - Record-time stabilization recipes: Provides copy-paste Playwright code for stubbing feature-flag scripts with 204 fulfills, mocking API responses, freezing the clock, dismissing overlays, triggering lazy content, and hiding unstable DOM regions. - App-side determinism patterns: Covers cases stubs cannot reach — SSR-time Math.random picks, infinite CSS animations, canvas/rAF loops — using an isUIVerify() branch and the UI_VERIFY env var. - Use Case: Your Next.js staging site's visual test flakes every run because a hero image is chosen by Math.random() at server render time; the skill directs you to pin the variant on isUIVerify() with UI_VERIFY=1 set on the app server so SSR and client agree. ## Quick Start Ask the agent to diagnose why my @uiverify/playwright visual test diffs keep flaking and apply the right determinism recipe to my test setup.

Frequently Asked Questions about playwright-visual-testing

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I fix flaky Playwright visual tests?▼

Identify what injects run-to-run variation and pin it before the snapshot: stub feature-flag and third-party scripts with page.route fulfilling 204, mock API responses with fixed fixtures, freeze the clock with page.clock.setFixedTime, and hide unstable DOM regions before capture.

How do I mock API responses in Playwright for visual testing?▼

Use page.route to intercept the API endpoint and fulfill it with a fixed JSON fixture so the same data renders every run. Register the route in beforeEach before navigation so the archived page always contains identical content.

Why does my visual test diff change every run with no code change?▼

The archive bakes in whatever the page was at capture time, so A/B variants, live data, timestamps, lazy content, or animations create diffs without real changes. Compare document.body.scrollHeight across runs to distinguish flag-driven reflows from layout noise.

Does reducedMotion in Playwright config stop CSS animations in captures?▼

No, setting reducedMotion at record time is a no-op because the archive never bakes computed transforms. The freeze happens replay-side via prefers-reduced-motion emulation, so the app's CSS must honor that media query with animation: none.

How do I handle Math.random in SSR frameworks for visual tests?▼

Pin the random pick in the component with an isUIVerify() branch and set UI_VERIFY=1 on the app server for the capture run so SSR and client agree. Seeding Math.random from a Playwright init script fails because it cannot reach server-side render choices.

Why should I use fulfill(204) instead of route.abort() to block scripts?▼

An aborted request reads as pending network activity and can hang the page's readiness wait. Fulfilling with status 204 completes the request empty, so the script resolves no variant and the page renders its control DOM.