Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I verify the name of a label in a table view using Instruments on iOS?

I'm using the Xcode "Instruments" tool to build automation for an iOS application and I need to verify that the label for an entry I've created in my app is correct.

The code listed below is, for some reason, not resulting in a solid pass or fail. Rather, when it runs, I get an "Issue" warning in the log and the test exits without explicitly closing.

I want to change my tests so that I check for the label name that I know is getting created, because I can see it with the AccessibilityViewer after my automation runs.

If the label is correct, then I want to log the test as a pass.

I've used UIATarget.localTarget().logElementTree() to map my element tree and I've used the AccessibilityInspector to verify the name of my label after my entry has been created. Trouble is, I just can't seem to get the syntax for verifying this correct.

My Accessibility Inspector has verified that the label name is: MyDogs! and it has the traits of Static Text and gives the Frame of {{114, 0},{166,480}}

By looking at the element tree--which I wish I could paste in here, it looks like the label would be found along this path:

\Target
-+
--\Application
---+
----\Window
-----+
------\TableView
-------+
--------\TableCell: name:MyDogs! rect:{0, 40},{480,166}}
---------|UIAStaticText: name:MyDogs! value:MyDogs! rect:{{0, 40},{480, 166}}
---------|UIAButton: name:story list share rect:{{439, 41},{33, 28}}

Can anyone tell me how the heck to verify this label?

My current code looks like this (but is not checking for the label--because I don't know how to):

var testName = "LoginCreateEntry";

//Start test logging
UIALogger.logStart(testName);

//This is supposed to target the entry that my automation has created.
//The flow goes, run the automation that creates the entry, then verify that the entry
//got created as expected and is visible to the user in the iPhone interface.

    var myEntry = target.frontMostApp().mainWindow().scrollViews().staticTexts()["My Dogs!"].value(); 

    var entryName = "My Dogs!";

//Do a bunch of UI automation here to create my entry, which results in the entry
//appearing in the mainWindow with the label: My Dogs!

//If myEntry evaluates to true, then call this test a pass.

if (myEntry === entryName) {    
UIALogger.logMessage("My entry was created!");

    //Mark the test as a PASS
    UIALogger.logPass(testName);
}
else {

    UIALogger.logMessage("My entry was not created!");

    //Mark the test as a FAIL
    UIALogger.logFail(testName); 
    }

//End test

Any feedback or help would be most appreciated!!

---------------------------------UPDATE--------------------------------------
Thanks all for your help! I actually got the value of the title and will display my solution below. But I CANNOT get the pass/fail logging functionality to work correctly no matter what I do--and the issue has been encountered by others as well. I keep getting the enraging

Issue: Script ended without explicting closing this test

message at the end of my tests. I'm becoming convinced it's a bug with Instruments.

Here's my updated test:

var target = UIATarget.localTarget();
var app = UIATarget.localTarget().frontMostApp();

var testName = "LoginCreateEntry";

//Start test logging
UIALogger.logStart( testName );

//Do lots of gui automation stuff here to create the entry which will appear in my app interface.
//I want to verify that the title I gave the entry matches what appears in the app interface

var window = app.mainWindow();
var tableView = window.tableViews()[0];
var tableGroup = tableView.groups()[0];
var entryName = "My Dogs!";

var myEntry = tableView.cells()[0].name(); //<-- This is what I needed!!!

UIALogger.logMessage("My Story Title: " + myEntry); //Print out entry name in log

if (myEntry === entryName) {    

    UIALogger.logMessage("My entry was created!");

    //Mark the test as a PASS
    UIALogger.logPass (testName);

} else {

    UIALogger.logMessage("My entry was not created!");

    //Mark the test as a FAIL
    UIALogger.loFails (testName); 

    }
//End test 
like image 827
Wulf Avatar asked Mar 06 '13 01:03

Wulf


2 Answers

I recommend using tuneup_js. With that library you can easily created test cases and check if the label exists and is equal to My Dogs

You can use it like this

test("LoginCreateEntry", function(target,app){
    //Create Entry
    //....
    var myEntry = target.frontMostApp().mainWindow().scrollViews().staticTexts()["My Dogs!"].name();

    //Check is Label is equal to My Dogs
    //Test "LoginCreateEntry" will fail if myEntry is not equal to My Dogs
    assertEquals(myEntry, "My Dogs");
});

P.S. you should use .name() and not .value() to get the name of the label

like image 165
Johan de Klerk Avatar answered Oct 20 '22 18:10

Johan de Klerk


At least as of summer 2012, and iOS 5, I found I could not access a UIA element by accessibilityLabel unless the accessibilityIdentifier was also set as well.

And unfortunately as of that time (and as of Xcode 4.2) the accessibilityIdentifier could only be set in code, not in Interface Builder. Not sure if things have improved since then. See this SO question for more info:

can I set accessibility identifier in interface builder? Xcode4.2

But as I mentioned, you can get UIA access by automationIdentifier to work if you have access to the source of the app, though. (Or can influence someone with access, I suppose!)

I have a project on github that shows how to set the accessibilityIdentifier on a UILabel (in the app source) and then write a UIA test that accesses the element successfully the way your code appears to be trying to do.

First up is my test file, where I try to locate a UILabel displaying the string "!":

https://github.com/billagee/UnicodeTapper-iphone4.2/blob/master/UnicodeTapperTests/tests.js

    // for iOS 5 - note 4 must be handled differently
    var charDisplayed = window.staticTexts()["bigCharLabel"].value();
    if (charDisplayed == "!") {
        UIALogger.logPass("Exclamation point displayed at startup");
    } else {
        UIALogger.logFail("Incorrect character displayed: " + charDisplayed);
    }

Then, in the target app's source, setting the UILabel's accessibility attributes looks like this:

// If device supports it, set accessibility identifiers for the UILabels
// in order to find them in UIAutomation easily.  Note that the
// accessibilityIdentifier can't be set in IB yet, as of Xcode 4.3.3;
// also, it's only supported in iOS 5 and up.
topBarLabel.isAccessibilityElement = YES;
bigCharLabel.isAccessibilityElement = YES;
if ([topBarLabel respondsToSelector:@selector(accessibilityIdentifier)]) {
    topBarLabel.accessibilityIdentifier = @"topBarLabel";
    bigCharLabel.accessibilityIdentifier = @"bigCharLabel";
} else {
    topBarLabel.accessibilityLabel = @"topBarLabel";
    bigCharLabel.accessibilityLabel = @"bigCharLabel";        
}

The full source is here:

https://github.com/billagee/UnicodeTapper-iphone4.2/blob/master/UnicodeTapper/UnicodeTapperViewController.m

like image 32
Bill Agee Avatar answered Oct 20 '22 17:10

Bill Agee