I wanna check whether there is a tableViewCell.detailTextLabel with a given string in my UITest. The problem is when I search for app.tables.cells.children(matching: .staticText) it will only look for labels that are tableViewCell.textLabel.
Any ideas on how to query for the detailTextLabel?
You can try a more generic query to determine if the text exists at all. If you are trying to assert that a cell contains "123 Main St.", for example, you can use the following:
let app = XCUIApplication()
XCTAssert(app.staticTexts["123 Main St."]).exists)
Granted, if that text appears in the textLabel the test will still pass.
It sounds like your detail text label isn't accessible.
To see everything that's available to your tests in the view hierarchy, print the debug description of the following query, which may help you to understand whether the element is appearing, what its type is, and what its identifier or label is:
let app = XCUIApplication()
print(app.descendants(matching: .any).debugDescription)
Make sure that the containing view (the cell?) is not accessible, and that the detail text label is accessible, and give it an identifier:
let cell = UITableViewCell!
cell.isAccessibilityElement = false
cell.detailTextLabel.isAccessibilityElement = true
cell.detailTextLabel.accessibilityIdentifier = "myDetailTextLabel"
Related
I'm a newbie to any type of iOS programming. I am trying to write UI test cases for one of my scenes.
Following is the code I'm getting when I use recode method and tap on the custom component.
let button = XCUIApplication().children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .button).element
In this custom component there are two buttons. I wanna know which button is selected. For that I need to identify the button. But i'm getting same code where ever I tap on the custom view.
How can I access each component inside custom view. Any help would be great.
Add an accessibility identifier to your custom view in the app's code.
let customView: UIView!
customView.accessibilityIdentifier = "myCustomView"
Then access the contents like this:
let app = XCUIApplication()
let customView = app.otherElements["myCustomView"]
let button1 = customView.buttons.element(boundBy: 0)
let button2 = customView.buttons.element(boundBy: 1)
XCTAssertTrue(button1.isSelected)
XCTAssertFalse(button2.isSelected)
Note that to make your test deterministic, you should already know which button(s) should be selected. This ensures that your test tests the same thing every time it is run.
You need to make you elements visible to Accessibility.
I would suggest you to watch the WWDC Session about UI Testing in Xcode especially this part
I am implementing UITests for my iOS app.
So far, I've been able to do some simple testing, but I've come to a tableView where there are two sections. Each section has a sectionHeaderView containing static text, eg. "SECTION 1" and "SECTION 2", in normal sectionHeader style.
When performing app.tables.staticTexts["SECTION 1"].exists it returns true. This is the first section, visible at the very top when the view loads.
When performing the same, but for "SECTION 2", it returns false. The sectionHeaderView for this section is outside the view at this point, so I thought this was the problem, but it turns out it's not..
I tried app.swipeUp(), which successfully brings the second section into the screen. After the swipeUp i sleep for a few seconds for the view to settle, and I perform the same check, but it simply cannot find the second sectionView.
After scrolling down, I have tried to print out app.tables.staticTexts.debugDescription to see what it can find, and it only shows the first section as well as a tableFooterView I have at the very bottom of the tableView.
At the time I perform app.tables.staticTexts["SECTION 2"].exists I can literally see the "SECTION 2" text on the simulator. Yet it does not exist to the test.
Why is my second sectionHeaderView completely invisible to XCTest? Could it be that I have disabled some sort of accessibility-variable on this view in particular? I can't find anything..
Edit, output:
t = 32.25s Find: Descendants matching type Table
t = 32.26s Find: Descendants matching type StaticText
t = 32.26s Find: Elements matching predicate '"SECTION 1" IN identifiers'
Found SECTION 1. Will scroll down to find Section 2.
t = 32.26s Swipe up Target Application 0x6080000bbf60
t = 32.26s Wait for app to idle
t = 32.30s Find the Target Application 0x6080000bbf60
t = 32.30s Snapshot accessibility hierarchy for my.bundle.identifier
t = 33.09s Wait for app to idle
t = 33.14s Synthesize event
t = 33.42s Wait for app to idle
Slept for 3 seconds. Have scrolled down. SECTION 2 in view now.
t = 38.86s Snapshot accessibility hierarchy for my.bundle.identifier
t = 39.64s Find: Descendants matching type Table
t = 39.65s Find: Descendants matching type StaticText
t = 39.65s Find: Elements matching predicate '"SECTION 2" IN identifiers'
t = 39.66s Assertion Failure: MyUITests.swift:347: XCTAssertTrue failed - SECTION 2 does not exist
t = 39.66s Tear Down
Place a breakpoint in your code at:
app.tables.staticTexts["SECTION 2"].exists
When you hit the breakpoint type this into the debug panel and hit enter:
po print(XCUIApplication().debugDescription)
This will list out everything that is available to XCUITest. Look for your Section 2 text in there. Often times when this happens to me, I spelled it wrong or the text in the app has an extra space somewhere. When using .staticText it has to match EXACTLY.
I ran into this problem for table footers. It seems like they are treated as "other" objects, not staticTexts so the following code should work:
XCTAssert(app.otherElements["SECTION 2"].exists)
Thanks to h.w.powers for the debugging tip:
po print(XCUIApplication().debugDescription)
A couple of questions, since I can't comment yet: (I've been doing a LOT of UI testing recently, so I'm learning a little)
What happens when you try to assert app.tables.staticTexts["SECTION 2"].exists after swiping up, and disregarding the "SECTION 1" label?
Is sectionHeaderView a custom subclass?
I've found it's helpful to assign specific views an accessibilityIdentifier and then access them via the XCUIElement proxy with that identifier.
Also, something I've found recently is that unless you're using UIAccessibilityContainer, referring to accessibility traits of superviews can negate the accessibility traits of its subviews.
Just put the debugger in the test function, run the test
and in debugger screen just write po app it will show the view hierarchy of your app containing images , static text etc.
I'm writting some UI Tests and I'm currently having a problem to match some text that is in a tableview cell.
So I want to test that a tableview has all the cases that it needs to have.
I tried it as follows:
if !app.staticTexts["sometext"].exists {
// FAIL
}
but this doens't work because it doesn't find the text and then I found something like this:
app.tables.cells.staticTexts["some text"].exists
and last but not least like this:
app.tables.cells.containingType(.StaticText, identifier: "some text")
But it seems that the is never finding the text and it is on the screen.
Someone knows how to get the text out of a tableview cell?
Set the accessibilityIdentifier on both your UITableViews, then you will be able to choose the right table every time.
app.tables["myIdentifier"].cells.staticTexts["some text"]
When the identifier for the cell is well defined - things will be in place. Try -
let app = XCUIApplication()
let tablesQuery = app.tables
XCTAssertTrue(tablesQuery.cells.containing(.staticText, identifier: "my identifier").staticTexts["Some Text"].exists,
"Failure: Something went wrong.")
This is using Xcode 7.2.1 and Swift 2.0.
I have a table cell containing a UILabel which is used to display an error message. So at initial load it is blanked using code like this:
cell.errorLabel.alpha = 0.0
cell.errorLabel.text = nil
Then later on when I've detected an error I want to display I do this:
cell.label.text = "to"
cell.errorLabel.alpha = 1.0
cell.errorLabel.text = "Error !!!!"
This works fine when running the app. However when running in a UI Test, I try to test that the error is being displayed like this:
let toCell = XCUIApplication().tables.... // Finds the cell with label 'to'
XCTAssertTrue(toCell.staticTexts["Error !!!!"].exists)
And it fails. I've verified I'm getting the right cell by checking the other ('to') label is present. Which it is. But the UI testing will not see the error label. I've tested this by adding a break point and using the debugger like this:
(lldb) p toCell.staticTexts.count
t = 427.03s Get number of matches for: Descendants matching type StaticText
t = 427.29s Snapshot accessibility hierarchy for enterprise.com.me
t = 427.31s Find: Descendants matching type Table
(UInt) $R2 = 1
t = 427.31s Find: Descendants matching type Cell
t = 427.32s Find: Elements containing elements matching type StaticText with identifier 'to'
t = 427.32s Find: Descendants matching type StaticText
The (UInt) $R2 = 1 indicating that there is one static text present. However looking at the simulator I can clearly see two UILabels.
I've tried a number of things individually to isolate the issue - Using just alpha or setting the text to nil, or using UIView's hidden property. Using any of these options to initially hide the label renders it invisible to UI tests when later made visible, no matter what I try.
I'm quite confused by this and I suspect it's a bug. Anyone have any ideas how to get UI Tests to see the UILabel once I make it visible?
P.S. I've also tried using a wait loop to wait for the label to appear (using expectationForPredicate(...), but the UILabel has not shown up.
Problem turned out to be that I had not set the accessibilityElements property on the cells. Therefore accessibility was having issues trying to figure out what was in each one.
So if you are building custom cells for a table view, ensure you set the accessibilityElements property so that testing can find the contents of the cells.
The question is actually really simple:
Is there a way to assert the displayed value from a specific label (e.g. UILabel) when using an accessibility label on this object?
As far as I see it, all the assertions (e.g. XCTAssertEquals) made in the examples, be it from a WWDC Talk or Blogposts, are only checking if an element exists for a query like XCTAssertEquals(app.staticTexts["myValue"].exists, true) or if the number of cells in a table is correct XCTAssertEquals(app.tables.cells.count, 5). So, when avoiding accessibility labels it's possible to check if an object has a certain value displayed, but not which object / element.
And when using accessibility labels, it robs me of the opportunity to query against the displayed values, because app.staticTexts["myValue"] will now fail to deliver a result but app.staticTexts["myAccessibilityLabel"] will hit.
Assuming I want to test my "Add new Cell to Table" functionality, I can test that there is really a new cell added to the list, but I have no idea if the new cell is added at the top or the bottom of the list or somewhere in between.
For me, an easy way to check if a specific element has a certain value should be a no-brainer when it comes to UI Testing.
It is possible that due to the missing documentation I might overlook the obvious. If so, just tell me.
Be sure to set the .accessibilityValue property of the UILabel whenever you set its .text value. Then in UITest, you can test the accessibility value like this:
let labelElement = app.staticTexts["myLabel"]
...
XCTAssertEqual(labelElement.value as! String, "the expected text")
I think you are asking a few different things, so I will try to answer each question individually.
Is there a way to assert the displayed value from a specific label (e.g. UILabel) when using an accessibility label on this object?
In short, no. UI Testing works by hooking into accessibility APIs, so you are limited to querying for objects based on that. You can, however, check the -value property of certain elements, such as controls. This is used to test if a switch is on or off. Note that these boil to down using accessibility APIs as well, just a different method (-accessibilityValue over -accessibilityIdentifier and -accessibilityLabel).
...but I have no idea if the new cell is added at the top or the bottom of the list or somewhere in between.
To interrogate an XCUIElement for its frame you can use the new XCUIElementAttributes protocol which exposes -frame. For example:
let app = XCUIApplication()
app.launch()
app.buttons["Add New Cell to Table"].tap()
let lastCell = app.cells["Last Cell"]
let newCell = app.cells["New Cell"]
XCTAssert(newCell.exists)
XCTAssert(newCell.frame.minY > lastCell.frame.maxY)
For me, an easy way to check if a specific element has a certain value should be a no-brainer when it comes to UI Testing.
If you think of everything in terms of accessibility this becomes a non-issue. UI Testing can only interact with your elements via accessibility APIs, so you must implement them. You also get the added benefit of making your app more accessible to user's with those settings enabled.
Try setting both the -accessibilityLabel or -accessibilityIdentifier for the cell to the displayed text. UI Testing can be finicky as to which one it uses.
It is possible that due to the missing documentation I might overlook the obvious. If so, just tell me.
XCTest and UI Testing don't have any official documentation. So I've gone and extracted my own from the header files exposed in the framework. Note than even though they were pulled from source, they are unofficial.
XCTest / UI Testing Documentation
What works for me is to set the accessibility identifier of the UILabel to let's say MyLabel.
func myLabelText() -> String {
let myLabelUIElement: XCUIElement = self.application.staticTexts["MyLabel"]
return myLabelUIElement.label
}
Tested with Xcode 8 and iOS 10
From the apple forums it looks like it is possible to get the value of the label:
The only way I've found is to not set an Accessibility Label, but use identifier instead. Then XCUIElement.label will change to match the current text of the label.
However there is a gotcha: if you have previously set Accessibility Label in XC, and remove it, an entry setting the label to "" remains in the storyboard. In this case, not only will calling .label will return "", but you won't be able to query for the label by it's text!
The only thing you can do is delete and re-add the label, or manually edit the xml.
lastobelus - https://forums.developer.apple.com/thread/10428