Testing a LottieAnimation in Compose
MainClock vs CompositionLocal + iterations/clipSpec
I recently used a CompositionLocal to test a Lottie animation rendered with Jetpack Compose, and I noticed there are different approaches to achieve my goal.
In this article I will be sharing three of those different approaches (MainClock, CompositionLocal of iterations and CompositionLocal of clipSpec) while sharing and explaining the code.
What are we starting with?
Suppose you have a Lottie animation that runs for half a second and plays a single time when required.
Note: we want to ensure the Lottie animation completes its cycle after starting.
The Composable displaying the Lottie animation uses a UI model with a boolean property to determine if the animation should be displayed or not.
data class LottieAnimationUiModel(val shouldShowAnimation: Boolean)
In order to show the Lottie animation I am using the LottieAnimation
Composable from the lottie-android library from airbnb.
MainScreen
is the main Composable. It needs a LottieAnimationUiModel
to decide wether to render the CustomLottieAnimation
, which in turn renders the LottieAnimation
.
Each LottieAnimation
needs two main parameters to render an animation: composition
and progress
.
In my case I used rememberLottieComposition
to load the animation file (LOTTIE_ANIMATION_FILE), and animateLottieCompositionAsState
to render the animation.
And now the idea is simple; I want to make sure that the animation is shown when the condition is met.
Building UI tests
There are different ways we can test the animation and confirm that it is shown when the UI model determines it. Here are three different approaches, though there might be other ways.
MainTestClock
Manually controlling the mainClock
in composeTestRule
I can jump to a specific frame using advanceTimeBy
and verify that the animation is displayed.
CompositionLocal + iterations
Using the iterations
parameter of the animateLottieCompositionAsState
. I am creating a private variable LocalLottieIterations
that will be used when creating the progress state.
By default,
animateLottieCompositionAsState
will iterate always once. Different animation scenarios may require different iteration setups.
In the production code, the value will be 1 because we want to show the animation only once.
In the test, the value is set to LottieConstants.IterateForever
because otherwise the animation will have finished by the time it checks if it is displayed.
CompositionLocal + clipSpec
All Lottie animations are controlled by a progress state which is handled by the animateLottieCompositionAsState
and by default, the progress goes from 0 until 1.
- 0: Animation has not started yet.
- 1: Animation has finished.
As you may have noticed, the Composable includes two log statements: one for value changes and one for when the animation finishes. This is how it looks like:
AnimationProgress: 0.0
AnimationProgress: 0.2401716
[…]
AnimationProgress: 0.9835604
AnimationProgress: 1.0
The animation has finished
The clipSpec
parameter in animateLottieCompositionAsState
lets us define which portion of the animation should be played. In other words, it lets us choose the beginning and end of the animation segment to play.
Using a CompositionLocal again, I am creating a private variable called LocalLottieClipSpec
that will be used when creating the progress state.
In the production code, the value is the class LottieClipSpec.Progress()
because it has the default values (0 and 1).
In the test, the values are set to minimum 0 and maximum 0.99 because the LottieAnimation
should never leave the screen.
The maximum value should be fine as long as it is < 1
I’m sure there are other great ways to test animations — feel free to share your approach in the comments or, even better, write about it! 😀
Want to come work with us at Just Eat Takeaway.com? Check out our open roles.