I have a UIViewController
subclass with a corresponding view designed in interface builder. In interface builder, I've set an accessibility identifier on two labels and Accessibility
as a feature is enabled for both.
I want to define my app flow in code, so I load the VC by let vc = storyboard.instantiateViewController(withIdentifier: storyboardIdentifier) as? MyVC
rather than by defining segues in IB.
In viewDidLoad
, I can confirm that .accessibilityIdentifier
is set.
And yet, in my tests, the elements cannot be found. This always returns false:
let app = XCUIApplication()
app.staticTexts["myIdentifier"].waitForExistence(timeout: 10)
If I then go on to print out the view hierarchy:
print(app.debugDescription)
→Application, 0x280e55960, pid: 1609, label: 'My App'
Window (Main), 0x280e55a40, {{0.0, 0.0}, {320.0, 568.0}}
Other, 0x280e55c00, {{0.0, 0.0}, {320.0, 568.0}}
NavigationBar, 0x280e55ce0, {{0.0, 20.0}, {320.0, 44.0}}, identifier: 'Thing'
Button, 0x280e55ea0, {{0.0, 20.0}, {62.0, 44.0}}, label: 'Back'
Other, 0x280e55f80, {{130.5, 32.0}, {59.5, 20.5}}, label: 'Thing'
Other, 0x280e56060, {{0.0, 0.0}, {320.0, 568.0}}
Other, 0x280e56140, {{0.0, 0.0}, {320.0, 568.0}}
Other, 0x280e56220, {{0.0, 0.0}, {320.0, 568.0}}
Other, 0x280e56300, {{0.0, 64.0}, {320.0, 504.0}}
Image, 0x280e563e0, {{0.0, 248.0}, {320.0, 320.0}}, identifier: 'imageName'
I didn't set the identifier on Image
- UIImage(named: "imageName")
has done that automatically. The labels of interest are descendants of a sibling of the Image
(i.e. grandchildren of Other, 0x280e56300
)
I've read various guides (1, 2) and believe I'm doing everything as I should, and yet the elements remain hidden to the test framework.
Edited to add:
Since the app being tested is in a separate process, I added a UIAlertController
to confirm the .accessibilityIdentifier
of the labels of interest when their parent view appears in the context of being driven by the UI test mechanism - they are definitely set, but the testing framework just can't see them.
Having painstakingly recreated the view step by step, confirming that elements could be found by their .accessibilityIdentifier
at every step along the way, it was the final wrapping in a UIStackView
that "broke" things.
That is, while everything worked with this view hierarchy:
+ View
Safe Area
+ View
+ Stack view
Label
Label (with identifier)
+ Stack view
Label
Label (with identifier)
Image View
Wrapping the plain view and image view in another stackview to achieve this:
+ View
Safe Area
+ Stack view <-- problematic stack view
+ View
+ Stack view
Label
Label (with identifier)
+ Stack view
Label
Label (with identifier)
Image View
... broke things. Backtracking one step and achieving the same wrapping in a different way did not break accessibility.
Broke: Selecting View and Image View in the view hierarchy tree, then choosing embed in stackview from the icon in the editor pane.
Did not break: Selecting View and Image View in the designer and then choosing embed in stackview from the icon in the editor pane.
I realise this is a very anecdotal answer (and having lost more than half a day to this I've no intention of going back to break it again!), but it seems the way in which views are selected prior to embedding in a stack view makes a difference.