Accessible Elements Guide ☑️
I've outlined some of the most relevant best practices related to iOS Accessibility for codebases with UI tests in this answer. Note that even though this answer is geared towards UIKit apps, the same best practices are framework agnostic between SwiftUI and UIKit (only with different API names).
Apply the same reasoning to SwiftUI accessibility View Modifiers to ensure a great User Experience for both types of apps.
I highly recommend paying attention to accessibility in apps because Apple promotes apps that enforce high accessibility standards, and supporting accessibility is more "ethical" software development by service to a wider audience.
Use .accessibilityIdentifier
I am writing this answer to advise others / OP/comments against using .accessibilityLabel interchangeably with .accessibilityIdentifier for the sole purpose of enabling UI Testing.
Use . accessibilityIdentifier rather than .accessibilityLabel because otherwise, we create a poor User Experience for VoiceOver users:
button.accessibilityLabel = "test" // ❌
reads to the user as "Button. test" which doesn't help the user navigate the screen if they are visually impaired!
button.accessibilityIdentifier = "test" //
Using the identifier means VoiceOver reads the Button's title label text rather than "test".
NB: If you are still unable to find the element, double-check you haven't overridden the .accessibilityIdentifier configuration in code in a storyboard or xib file. Also check the button is an accessibility element in both places.
Enabling UI testing for buttons within container views
You may be unable to locate a button in UI tests because it's a subview of an accessible element. In order to enable accessibility on the button for UI tests and VoiceOver for the container, use .accessibilityElements instead:
containerView = UIView()
containerView.isAccessibilityElement = false
containerView.accessibilityElements = [firstLabel, secondLabel, button]
// These elements are subviews of containerView
Setting .accessibilityElements makes the parent view an Accessibility Container! The advantage here is that we get UI tests as well as an accessible VoiceOver User Experience that allows users to select/navigate within subviews too.
Screen readers go through the elements on a page/screen in the order in which they appear. Set the order you want VoiceOver to read the elements within the .accessibilityElements property.
.isHittable in UI Tests
We can now find the button with a simple XCUIElementQuery subscript:
XCTAssertTrue(app.buttons["test"].isHittable)
I recommend using .isHittable as outlined in this answer, rather than .exists because it provides a more robust test. We can see why from the docs:
isHittable returns true if the element exists and can be clicked,
tapped, or pressed at its current location. It returns false if the
element does not exist, is offscreen, or is covered by another
element.