testing-animations-deterministically
Installation
SKILL.md
Testing Animations Deterministically — autoAdvance = false Or Bust
A Compose animation test that does not pause the clock is by definition flaky. With mainClock.autoAdvance = true (the default), the framework's InfiniteAnimationPolicy throws CancellationException as soon as an indeterminate animation starts, and finite animations finish in a single auto-advanced burst with no observable intermediate state. This skill teaches the five-line recipe that fixes that, plus the runOnUiThread-vs-runOnIdle gotcha that bites every developer who tries it for the first time.
When to use this skill
- The test asserts an intermediate frame of an animation (mid-fade alpha, mid-scroll offset, mid-Crossfade dispose).
- The composable contains an indeterminate animation (
LinearProgressIndicator()with no progress argument,rememberInfiniteTransition, loopingwithFrameMillis). - The developer reports
CancellationException("Infinite animations are disabled on tests")and asks how to make it stop. - The developer reaches for
Thread.sleep(500)to "wait for the animation". - The developer's animation test passes locally and fails on CI, or vice versa.
- The developer mentions
autoAdvance,advanceTimeByFrame,advanceTimeBy,Crossfade, "flaky animation test", orInfiniteAnimationPolicy.
When NOT to use this skill
- The animation is a side effect; the test only cares about the final state. Default
autoAdvance = trueis faster — see../synchronizing-with-idle/SKILL.md. - The clock semantics themselves are unclear (frame model, rounding rules, v1 vs v2 dispatcher). Read
../controlling-the-test-clock/SKILL.mdfirst. - The condition under test is not Compose state (a
Job.isCompleted, aMockito.verify). UsewaitUntilor anIdlingResourcefrom../synchronizing-with-idle/SKILL.md. - The test uses screenshot comparison waiting on the RenderThread for ripple/elevation pixels. That is the one legitimate
Thread.sleepsite (skydoves hot take #7).