Search code examples
iosswiftuilabelxcode-ui-testing

iOS UI testing - UILabel *with* accessibilityIdentifier cannot be found


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.


Solution

  • 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.