Unfortunately there is no direct named method to access parent elements similar to children()
and descendants()
provided by Apple but you were actually on the right track with containing()
. There are two ways I usually approach it when I need to locate a parent element based on children/descendants:
- Using
containing(_:identifier:)
let parentElement = app.otherElements.containing(.textField, identifier: "test").firstMatch
or
let parentElement = app.otherElements.containing(.textField, identifier: "test").element(boundBy: 0)
- Using
containing(_ predicate: NSPredicate)
let parentElement = app.otherElements.containing(NSPredicate(format: "label CONTAINS[c] 'test'").firstMatch
or
let parentElement = app.otherElements.containing(NSPredicate(format: "label CONTAINS[c] 'test'").element(boundBy: 0)
These are just examples with random data/element types because you didn't mention exactly what you want to achieve but you can go from there.
Update:
As usual the Apple documentation doesn't do a good service. They say 'descendants' but what they actually mean is both direct descendants(children) and non-direct descendants(descendants). Unfortunately there is no guarantee and there is no generic solution. It should be based on your current needs and the application implementation. More examples that could be useful:
- If you don't want the first element from the query you are better off using
element(boundBy: index)
. So if you know that XCUIElementQuery will give you 5 elements and you know you need the 3rd one:
let parentElement = app.otherElements.containing(.textField, identifier: "test").element(boundBy: 2)
- Fine graining of your element locators. Lets say you have 3 views with identifier "SomeView", these 3 views each contain 2 other subviews and the subviews have a button with identifier "SomeButton".
let parentViews = app.otherElements.matching(identifier: "SomeView")
let subView = parentViews.element(boundBy: 2).otherElements.containing(.button, identifier: "SomeButton").element(boundBy: 1)
This will give you the second subview containing a button with identifier "SomeButton" from the third parent view with identifier "SomeView". Using such an approach you can fine tune until you get exactly what you need and not all parents, grandparents, great-grandparents etc.
I wish Apple provided a bit more flexibility for the locators with XCTest like Xpath does for Appium but even these tools can be sufficient most of the time.