Mobile Software Test Automation: Interacting with objects for iOS

Last week we went through a few different touch methods for android.  You will remember one important concept is that any element you can find via query, you can interact with via the gesture methods we will discuss today.  Now we will jump into the same for iOS as the methods differ slightly.  There will be a little bit of crossover, mostly in the predefined steps.  So let's get started.

Touch Methods

You all should remember the basic touch method from when we developed page support for the sample calculator iOS app:

touch("UIButton text:'9'")

That will get you through a basic app, like a calculator, but we know that there are a lot more ways users interact with smartphones these days.

Double Tap

Using the double tap gesture will look the same as android. Here it is:

double_tap("UIButton marked:'Save'")

Long Press

Here is where we start to deviate a bit.  Although this had been a gesture android had been using for a while, it was recently added to iOS, hence a little bit different name: touch and hold. Here is an example:

touch_hold(uiquery, options = {})

Here, the uiquery is the same query string we use to locate any object on the screen.  You will notice that there is also an options hash.  This is actually available on most touch methods, but they mainly only accept an :x and :y key that offsets the touch based off those values.  The options hash for touch and hold also accepts a duration parameter.  The default duration is 3 seconds, so if you need more than that, you will need to use this option.  Here is an example from the Calabash iOS API:

touch_hold("webView css:'input'", duration:10, offset:{x: -40})

Two Finger Tap

Here is a touch method that we have for android, but it's use is not as widespread. Here is the implementation:

two_finger_tap("UILabel {text CONTAINS[c] 'sample text'}")

Tap Mark

Here is one useful touch method that I didn't mention for android, but they are used the same way.  Basically, in any instance where you use the query string "* marked:'something'", you can use this as a quicker way of defining it:

This is equivalent to touch("* marked:'#{label}'")

Wait Tap

This method actually removes a huge chunk of code, and wraps it all into one.  In the past, you may have had to wait for an element to appear, then wait for animation to complete, and then touch the object.  Now, all you have to do is wait tap:

wait_tap(uiquery, options = {})

The options hash here, allows for the usual offset, but also timeout, which is the number of seconds it waits for an element to appear (default 3), and frequency, which is the polling frequency for checking if the view is present (default 0.2).

Touch by Coordinates

At first, I wasn't sure I wanted to even mention this, because it should only be used out of absolute desperation.  But I will confess, on a previous project, I had to use this because we were using a legacy tab controller which wrapped the whole tab bar in an object, and calculated the touch coordinates to determine where you actually pressed.  Terrible, i know, but it's how it used to be done long ago.  It was very fragile, and tests failed if I used a phone with a bigger screen.  Anyways, you have been warned...

tap_point(x, y)

That wraps up the touch methods I feel are useful.  I did skip over a few, so if you are interested, you can see them all in the Calabash iOS API


Just like last week, remember that you can only interact with an element that's in view.  For the most part, the center of the object has to be in view for you to interact with it.  So here's how we can expose those elements:

Basic Swiping

Here are the predefined swipe steps that you can use by simply adding them to your .feature file. 

When I swipe up
Then I swipe down
And I swipe right
Then I swipe left

These will work great so long as the scroll view you are wanting to swipe is the first one on the screen.  Otherwise, we will need to make a custom step.

Advanced Swiping

An example of when this would be useful is when performing the swipe to delete gesture, which is common on most iOS messaging apps.  

In my opinion, the best option for swiping on a scroll view is to use the swipe method.  It will accept in the options hash, an offset, uiquery, and force, which gives you just about everything you will need.  The only disadvantage is that this isn't reliable for some scroll views on simulators below 9.0. But it works great on physical devices and simulators >= 9.0.  Here is an example:

swipe(dir, options = {})
swipe(:left, offset:{x:10,y:50}, query:"UITableViewCell", force:strong)

In this method, the first parameter is the direction, and can accept left, right, up, or down.  It can be passed an options hash that includes an x,y offset, uiquery, and force.  You know all about the offset and uiquery already.  The force option allows for strong, normal, and light, with the default being normal.  The force is not perpendicular pressure on the screen, but length of the swipe.

Another option would be to use the scroll method, and scrolls half the frame size:

scroll(uiquery, direction)
scroll("UITableView", :down)

One important thing to note about scroll is, it is implemented under the hood differently from the swipe method.  This is important because this method can actually do things that a real user cannot, so I would use this with caution. 

Wrapping up

This finishes our section on advanced gestures.  We have come a long way, but there is still so much more to cover!  Next week we will go over how to update calabash gems and dependencies, as well as updating that gem in the iOS project.  We will them move onto using tags, and then integration into a CI process.  See you next week!