Mobile Software Test Automation: Wait helpers

Now that we are past the setup stage, we get to move on to some more fun stuff.  For our sample app, I briefly mentioned some of the more advanced steps such as wait helpers, but I want to take a little deeper dive into them, as you may need to be a little more creative for your specific app.  

Wait Helpers

Background

Let's face it, it's almost impossible to escape the need to wait for an element to appear, or for animation to complete.  This can be true for both web and mobile automation, so don't feel alone.  As an easy fix, you may be tempted to insert the below code into the do block of a step definition:


sleep(1)

The number inside the parenthesis can be any positive number (including decimals), which represents the seconds that the current thread is suspended.  This is equivalent to Thread.sleep for those of you that use selenium-java.  I say that to say this...DON'T USE THIS UNLESS ABSOLUTELY NECESSARY! 

It will work, but in practice, it should be at the bottom of your barrel of code to use.  If you run a regression test against differing network speeds, your sleep steps would have to be so long that your tests against normal network speeds crawl, or your slow network tests fail.  And when you start integrating these tests as part of a CI process, we are talking delaying a deploy way longer than necessary...not good.  Don't get me wrong, there may be a time and a place for this code.  I have used it in the iOS launch hooks for one of my projects because there were so many background processes that kicked off when the app closed between scenarios, that i needed a pause.  But it shouldn't be standard practice.

A better solution

Instead of using the sleep method, calabash has included all sorts of intelligent wait helpers to fit every need.  These will work with your app on both a slow and fast network speed, and allow the test to run as quickly as possible, so the tests don't un-necessarily hold up a deploy.  You can also specify a few options, such as timeout, so that you can tailor the method to best fit your app.  The exhaustive list of wait helpers can be found via the calabash API here, but I will discuss the ones I most commonly use next.

First up, wait_for_element_exists.  I'll show the basic implementation, as well as an example:


wait_for_element_exists(element_query, options = {})

wait_for_element_exists("UIButton marked:'Settings'", timeout: 60)

Isn't this great?!?  Instead of simply pausing the thread for however long with the sleep method, you can wait until some element exists on the screen, like a button, or some text.  And the timeout can vary, based off your needs.  The default is 30 seconds, so if you need more than that, you will need to specify.  Also, the options hash will accept the following parameters:


:timeout (Numeric) — default: 30 — upper limit on how long to wait (in seconds)
:retry_frequency (Numeric) — default: 0.3 — how often to poll (i.e., call the given block)
:post_timeout (Numeric) — default: 0 — if positive, an extra wait is made after the condition is satisfied
:timeout_message (String) — the error message to use if condition is not satisfied in time
:screenshot_on_error (Boolean) — generate a screenshot on error

Similar to the previous method, we have wait_for_element_does_not_exist. Here is the basic implementation:


wait_for_element_does_not_exist(element_query, options = {})

This one is very similar to the previous method, except, waiting for an element to disappear.  Pretty self explanatory. 

Finally, my personal favorite...when_element_exists.  The implementation is the same as the others:


when_element_exists(element_query, options = {})

The great thing about this method is that it is basically a two for one special.  This is basically using the standard wait_for_element_exists method, and once it appears, the default is to touch the element.  In short, this will wait for an element to show up, and then touch it.

Wrapping up

There are obviously more wait methods than what i mentioned, but this should get you in the right direction.  Just remember, try to use these smarter methods in place of the sleep method.  They really will help speed up your tests, and make them less fragile.  Now get out there and start putting these to work!  I'll see you next week with some more on advanced queries, to help you best locate the single element you need.