Skip to main content
ExodeUI

EXODEUI DESKTOP

A little space for good ideas.

Choose your platform to get the official ExodeUI installer.

Looking for Intel Mac or other builds? Explore the web studio or check all download options.

Prefer the browser? Try for free in your browser →
Tutorial · Testing7 min read·Updated October 2026·By the ExodeUI team

Testing UI States and Animations with Playwright

How to write stable tests for animated UI with Playwright: controlling time with page.clock, emulating reduced motion and dark mode, and screenshots with animations disabled.

Direct Summary & Definition

Core Takeaway

Make animation tests deterministic: control time with page.clock, which covers timers, requestAnimationFrame and performance; emulate user settings with page.emulateMedia({ reducedMotion, colorScheme }); assert on states rather than mid-animation pixels; and take screenshots with animations disabled. Test the reduced-motion path as a first-class case.

Why animation tests are flaky

Animations depend on time, and real time varies between runs and machines. A screenshot taken 10 milliseconds early or late shows a different frame. The fix is to control time and settings, and to test the states animations move between rather than individual frames.

Four steps: set state, control time with page.clock, emulate settings such as reduced motion, assert with DOM checks and screenshots
Fixed time and fixed settings make animated UI testable.

Control time

Playwright's Clock API lets a test install a fake clock and then pause, fast-forward or run time for a set duration. It covers setTimeout, setInterval, requestAnimationFrame and performance, so you can, for example, fast-forward past a loading delay and check the success state appears.

Emulate user settings

page.emulateMedia() can set reducedMotion to "reduce" and colorScheme to "dark" or "light". Run key flows with reduced motion on to confirm that nothing important depends on animation, and in both themes to catch contrast problems.

Stable screenshots

Playwright Test can compare screenshots with expect(page).toHaveScreenshot(), and screenshot options include animations: "disabled", which stops CSS animations and transitions for the capture. Use visual comparisons for end states, and DOM or accessibility assertions for behaviour.

Testing canvas-based components

Canvas animations, such as those drawn by Lottie, Rive or ExodeUI runtimes, are not visible in the DOM. Test the inputs your code sends and the events it receives, keep real accessible elements alongside the canvas, and use screenshots for visual checks after time is controlled.

Production Implementation Snippet

Interactive Component Implementation
import { test, expect } from '@playwright/test';

test('save button shows success, also with reduced motion', async ({ page }) => {
  await page.clock.install();                         // fake timers + rAF
  await page.emulateMedia({ reducedMotion: 'reduce' }); // test the calm path
  await page.goto('/settings');

  await page.getByRole('button', { name: 'Save' }).click();
  await expect(page.getByRole('status')).toHaveText('Saving…');

  await page.clock.runFor(2000);                      // skip the wait deterministically
  await expect(page.getByRole('status')).toHaveText('Saved');

  await expect(page).toHaveScreenshot('saved.png', { animations: 'disabled' });
});

Key Principles to Remember

  • Control time with page.clock (timers, requestAnimationFrame, performance)
  • Emulate reducedMotion and colorScheme with page.emulateMedia
  • Assert on states and accessible text, not mid-animation pixels
  • Screenshot with animations: "disabled"
  • Test the reduced-motion path as a first-class case

Frequently Asked Questions

Sources

  1. Clock — Playwright docs
  2. Page.emulateMedia and screenshot options — Playwright docs
  3. Visual comparisons — Playwright docs

Related Guides & Examples

Components built around testable states

ExodeUI components are driven by named inputs, which makes their states easy to test from your code.

Read the React guide
Try for free