Making Your Appium Tests Fast and Reliable, Part 7: Disabling Animations
This article is the seventh in a multi-part series on test speed and reliability, inspired by a webinar I gave on the same subject (you can watch the webinar here). You might also want to check out the previous episodes on Test Flakiness, Finding Elements Reliably, Waiting for App States, Dealing With Unfindable Elements, Setting Up App State, and Advanced Capabilities.
The best mobile apps are designed not only to function well, but also to look good. Beyond the importance of a truly "usable" UI, eye candy sprinkled judiciously throughout your app has the potential to make it stand out and give that extra bit of delight to your human users. This eye candy, tasty though it might be for us humans, is completely wasted on Appium. Appium is a completely non-aesthetically-inclined robot, and doesn't care whether your app is skeuomorphic, materialed-out, or chock full of whatever weird animations the kids are into these days.
The last point is especially salient: animations take time. And unless you're directly trying to test those animations, the time spent waiting for them to complete is completely useless. Actually, it's worse than that! Animations can add instability to your testing by creating race conditions (the kind you have to work around using explicit waits or similar). Finally, animations take up precious CPU, which can also end up reducing the reliability of your device under test. What would be great is if we could simply do away with them entirely when Appium is running its tests, since they serve no useful purpose. And we can!
Disabling Default or System Animations
If you do some spelunking on the internet, you'll find lots of articles on disabling animations for Android devices. They usually involve a series of manual steps involving turning on developer mode, and tapping through a bunch of menus. This is fine if you don't mind manually interacting with your phone or emulator, but often it's better to do things programmatically, if possible. Luckily, we can make the magic happen with a set of
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0
These commands work on emulators and real devices, without requiring root. Basically, they walk through each of the system animation properties and set their values to
0, meaning we want to turn them off completely. (To reset the settings to the default, we can run the same commands with a value of
1 in each case).
If you run these commands, then interact with your device, you'll notice that there are no more visible transitions between apps, etc... Congratulations, you sped up your Android experience!
On iOS, we're not in quite as fortunate a situation. We can reduce system animations somewhat, but we can't turn them off completely, and we can't even reduce them programmatically---at least not very quickly. The way to "disable" animations on iOS is as follows:
- Open Settings
- Tap "General"
- Tap "Accessibility"
- Tap "Reduce Motion"
- Flip the switch to "On"
As you can tell by the name of the setting we're dealing with, we're only "reducing" the motion involved in certain transitions on the device. Since this all takes place in the Settings app, we can actually use Appium to take these steps by writing an Appium script to find and tap the appropriate elements. However, doing so would obviate any benefit of time saved due to minimized animations, unless you have a lot of tests and can do this only one time in the device setup routine before testing begins.
Disabling App-Specific or Custom Animations
Disabling system-wide animations is a good idea, but this doesn't always catch every type of animation. Apps can define their own animations, too. To deal with your app specifically, we can make use of a tip (once again supplied by long-time Appium Pro reader Wim) that involves custom app logic based on whether your app is being built for testing. This does mean you'll need the ability to commit code to the app itself, or ask the app developers to do this.
Here's how it works: most animation libraries and methods take a timing parameter, which specifies how long the animation is meant to take. What we want to end up with is a build of the app where each of those timings is specified to be zero. I won't show code examples for how to do this, because it depends on your app platform and framework (iOS, Android, React Native, etc...), but for example have a look at Apple's documentation for the UIViewPropertyAnimator. The
init method takes a
Basically, the call to a method like this should be wrapped in another function which checks to see if the app is in testing mode (via some internal flag or environment variable; it's up to you). If it is, the function will return zero for any time interval. Otherwise, it will return the developer-specified value for that animation. The net result will be that all your animations will take no time at all, effectively disabling them completely. Depending on your app framework, you might be able to come up with an even simpler and more elegant solution than this sketch.
By disabling all possible animations using these two types of technique, you'll save a lot of time and add a bit of reliability back into your build. How much time you save depends on your app and how it uses animations, but every second you shave off your tests is a second shaved off your developer cycle as a whole, which brings benefits to everyone that relies on your build.