简体   繁体   中英

iOS XCUITests access element by accessibility

How do I assert a button exists by his accessibilityLabel or identifier?

func testExitsButton() {
    XCTAssertTrue(app.windows.containing(.button, identifier: "Button Text").element.exists)
    XCTAssertTrue(app.buttons["Button Text"].exists)
    XCTAssertTrue(app.buttons["test"].exists) <- I want this, instead of accessing the text property I want by specific id, maybe the text property override the accessibilityLabel?
}

在此处输入图像描述

Set an accessibility identifier in your application code, and then search for the button using that identifier in your tests.

// app code
let button: UIButton!
button.accessibilityIdentifier = "myButton"

// UI test code
func testMyButtonIsDisplayed() {
    let app = XCUIApplication()
    let button = app.buttons["myButton"]
    XCTAssertTrue(button.exists)
}

The accessibility identifier is set independently of text on the button, and is also independent of the accessibility label. It's not best practice to put identifiers for UI elements as the accessibility label , since the accessibility label is read to VoiceOver users to explain the element to them.

IMPORTANT NOTE : If a superview is set to accessible, XCUITest might not be able to access its subviews.

You can access the element by setting its accessibility via the storyboard or programmatically as discussed above. You can click the record button when your cursor is in a function which starts with the prefix "test" in order to record how XCUITest sees an element. Sometimes it takes a couple cleans (command shift k) and a couple minutes for the record button to be available. You can also step down your tree from storyboard and use XCUITest functions such as element(boundBy: Int), children(matching: .textField), you can chain them as well: XCUIApplication().tables.cells.containing(.button, identifier: "id"). After that is the easy part, use .exists which returns a boolean.

在此处输入图片说明

add | "accessibilityIdentifier" String test | in the User Defined Runtime Attributes on the navigation bar, instead of in the accessibility label

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

I got the same issue because the keyboard covered the button so:

app.buttons["Done"].tap()

solved the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM