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

2

6

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 
Ronel answered 6/3, 2013 at 1:45 Comment(2)
I made some tweaks to your question to bring it in line with general style preferences on SO as well as give you more focused tags, I hope this helps you get good answers. Great question btw!Korn
Something that might be interesting for future cases like this - if you find the answer on your own, it's apparently OK to post the answer on SO and accept it. :) See meta.stackexchange.com/questions/17845/…Kiki
S
5

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

Sensation answered 6/3, 2013 at 6:41 Comment(1)
Thanks very much! Turns out this is what I needed: var myEntry = tableView.cells()[0].name();Ronel
K
5

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

Kiki answered 6/3, 2013 at 6:55 Comment(2)
This info was passed onto our Dev team and was very useful. It's obvious that the app under test was not designed with automation in mind so this has been a learning experience for everyone. iOS apps meant for mass distribution need to be designed with automation in mind from the get go.Ronel
Glad it was helpful! If this answer and the other poster's answer were helpful, upvoting them is always appreciated. Which reminds me, I should upvote your question.Kiki

© 2022 - 2024 — McMap. All rights reserved.