I’m developing Fatigue Survey, our first iPad application that allows aircraft crew to report their current fatigue status from iPads whilst the aircraft is in flight.

As all required features were completed, I decided to set up some automated UI tests. Starting from iOS 4, Apple introduced UI Automation for iOS devices. In simple words you can write a test, using JavaScript, and run it against your iOS application. The script is able to select the application’s options, populate text boxes and push the buttons. It’s a very valuable addition to the development environment, as it allows you to setup automated tests quite easily. However it seems that it is lacking some documentation, and there are still some bugs too.
Because I couldn’t find any other tutorial on how to deal with alerts properly, I decided to share my experience with you. I’m using Xcode 4 and iOS 4.3.

Here’s the alert I was dealing with :

Basically, the code in Objective-C behind showing this alert is as follows:

alert = [[UIAlertView alloc] initWithTitle:@"Saving error"
            message:message
            delegate:self
            cancelButtonTitle:@"OK"
            otherButtonTitles:nil];
alert.accessibilityLabel = @"errorAlert";
//alert.isAccessibilityElement = YES;
[alert show];

The first line (which is 5 lines in fact) is simply the initialization of our alert with a given title, message from a variable and a single button to close it. On the next line we are assigning a string based identifier to be able to identify the alert during the test. The third line is quite interesting: Apple’s documentation suggests that isAccessibilityElement should be set to YES to enable it to be accessible via the identifier during the test. Unfortunately it didn’t make any difference for me. I tried it with both YES and NO with no change in behavior. The last line is just showing our alert to the user.

In UI Automation we need to provide some JavaScript code to handle the alert. On Apple’s website I found the following example of the alert handler:

UIATarget.onAlert = function onAlert(alert) {
   var title = alert.name();
   UIALogger.logWarning("Alert with title '" + title + "' encountered.");
   if (title == "The Alert We Expected") {
       alert.buttons()["Continue"].tap();
       return true; //alert handled, so bypass the default handler
   }
   // return false to use the default handler
   return false;
}

The most interesting line of the code is tapping the button. Method alert.buttons() returns all buttons from a parent UI element (alert in this case). [“Continue”] selects the desired button and tap() simulates tapping it by the user. This code looks fairly straightforward and ready to be amended for our purpose. The only problem is, it doesn’t work. I just couldn’t get any buttons from the alert. Because of that I couldn’t dismiss the alert and continue the test. This is probably a bug in the UI Automation framework.
On StackOverflow I found a suggestion that method UIATarget.localTarget().tap({x:positionX,y:positionY}); can be used to tap the screen at any coordinates. The only problem was that my alert was variable height. This is because several number of errors could be displayed on the alert.
Finally I came up with following solution:

UIATarget.onAlert = function onAlert(alert){   
   var name = alert.name();
   UIALogger.logMessage("alert "+name+" encountered");
   if(name == "errorAlert"){
       var positionX = 500;
       for(var positionY=300; positionY<600;positionY+=10){
           target.tap({x:positionX,y:positionY});
       }
       return true;
   }
   return false;
}

What I did is create a loop based on an empirical value that taps various parts of the screen. The reason for this is to click the “OK” button and dismiss the alert in the result. You might think this is not an elegant solution (I would agree with that), however it was the only solution that worked for me. Additionally it simulates a bit of random user input and random user input is what would happen in real life, wouldn’t it ?

Let me know if you have similar experiences with automated tests of iOS applications or any suggestions how to make this solution (even) prettier ;-)

Author: Marcin Mojciechowski

Related Posts:
Line Engineer AR
iPad vs Android
iPhone vs Android App Fight