Visual regression: non-deterministic rendering (fonts, animations, dates) in CI
A screenshot is only stable if the page renders identically every run. Clocks, relative dates, animations, spinners, blinking carets, and randomized data all change the pixels without any code change, producing false diffs. Freeze them before capturing.
What this error means
Visual tests fail intermittently across tools (Playwright, jest-image-snapshot, Percy) with diffs on timestamps, a spinner frame, a moving carousel, or a text caret. Re-running produces a different result.
# diff clusters on:
# - "Updated 2 minutes ago" text
# - a loading spinner captured mid-rotation
# - a blinking text caret in an inputCommon causes
Time and dates rendered live
A visible clock or relative timestamp changes every run, so the captured pixels differ even though nothing in the code changed.
Animations, spinners, and carets not frozen
Anything in motion at capture time is caught at a different frame each run, and a blinking caret toggles on or off between captures.
How to fix it
Freeze time and disable motion
Pin the clock, disable CSS animations and transitions, and hide the caret before capturing.
await page.clock.setFixedTime(new Date('2026-06-30T12:00:00Z'));
await page.addStyleTag({ content: '*{animation:none!important;transition:none!important;caret-color:transparent!important}' });Seed random data and wait for readiness
Use a fixed random seed and wait for network idle and fonts before capture so the content is deterministic.
await page.waitForLoadState('networkidle');
await page.evaluate(() => document.fonts.ready);How to prevent it
- Freeze the clock and seed randomness for every visual test.
- Disable animations, transitions, and the caret at capture.
- Wait for fonts and network idle before taking the screenshot.