Utilities for easier interaction with XCUITest methods

What's New



Utilities for easier interaction with XCUITest methods.

What's included

  • XCUIElement extensions:
    • Checking existence of elements:
      • assertExists()
      • assertNotExists()
    • Checking interactivity of elements:
      • assertIsHittable()
      • assertIsNotHittable()
      • assertIsEnabled()
      • assertIsInteractive()
      • assertIsNotInteractive()
    • Checking properties of elements:
      • assertHasLabel("label")
      • assertContainsText("label")
      • assertHasValue("equatable value")
      • assertHasPlaceholder("placeholder")
    • Waiting for interactivity:
      • waitForInteractivity()
      • assertExists(waitForAppToIdle: true)
    • Checking traits of elements:
      • assertIsSelected()
      • assertIsNotSelected()
  • XCUIApplication extensions:
    • Checking foreground state:
      • assertIsInForeground()
      • assertIsNotInForeground()
    • Performing actions:
      • moveToBackground()
    • Accessing other apps:
      • XCUIApplication.safari
  • XCUIElementQuery extensions:
    • Checking number of elements:
      • assertHasCount(2)
      • assertNotExists()

All of the above have optional message as last parameter that can be used to configure what is displayed if assertion fails. For example: element.assertExists("My element should be visible").


Here is a short example from one of my apps that makes use of this library. In the test I am checking that it is possible to navigate to "Premium features" screen, verify that most important data is visible and check that it is possible to leave that screen.

Note that some of the buttons are identified by enum case instead of raw string. You can see type safe identifiers tip below to see how this is implemented.

func testOpenClosePremiumScreen() throws {
    try launch(configuration: .init(premiumUnlocked: false)) // TODO: Add tip about helper launch configurations

    app.buttons["Unlock Premium"].waitForInteractivity().tap()
    app.buttons[.unlockFeaturesButton].assertIsEnabled().assertContainsText("Lifetime access")
    app.buttons["Restore Purchase"].assertIsEnabled()

    app.staticTexts["Pipilo Premium"].assertNotExists()


Swift Package Manager

  1. Add the following to the dependencies array in your Package.swift file:
.package(url: "https://github.com/Tunous/XCAppTest.git"),
  1. Add XCAppTest as a dependency for your tests target:
.target(name: "MyAppTests", dependencies: ["XCAppTest"]),
  1. Add import XCAppTest in your tests source code.


Add https://github.com/Tunous/XCAppTest.git, to the list of Swift packages for your project in Xcode and include it as a dependency on your tests target.


Type safe identifiers

To make interaction with elements easier, you can introduce a helper enum that will act as a type safe accessibility identifier. That way you will avoid typos when trying to match user interface elements from your tests.

  1. Create ElementIdentifier.swift file with following contents and include it in both your source and tests targets:
public enum ElementIdentifier: String {
    case exampleButton
    // More identifiers can be added here

extension View {
    public func accessibilityIdentifier(_ id: ElementIdentifier) -> some View {
        return self.accessibilityIdentifier(id.rawValue)
  1. In tests target add helper extension to match element by this new identifier:
extension XCUIElementQuery {
    public subscript(_ id: ElementIdentifier) -> XCUIElement {
        return self[id.rawValue]

    public subscript(_ id: ElementIdentifier, boundBy index: Int) -> XCUIElement {
        return self.matching(identifier: id.rawValue).element(boundBy: index)
  1. In your views use the new ElementIdentifier instead of String as accessibilityIdentifier:
struct MyView: View {
    var body: some View {
        Button("My button", action: {})
  1. Access mentioned button in your tests:
func testTapButton() {
    let app = XCUIApplication()


  • Swift Tools 5.6.0
View More Packages from this Author


  • None
Last updated: Sun Feb 05 2023 02:29:52 GMT-0500 (GMT-05:00)