XCUITests — Why & How to apply WAIT for element to fulfil Expectations?

Nishith Shah
Quality Engineering University
3 min readApr 12, 2021

Wait is an important command used in XCUITests Automation for handling dynamic loading of UI Controls on a mobile application. Wait command in XCUITest helps to ensure that our mobile application is less flaky and is more reliable.

Flaky tests

Unreliable tests, also known as a ‘flaky tests’ are typically characterised by a test that can both pass and fail on subsequent executions without any changes to code. Such tests can introduce wastage in the software delivery life-cycle when verifying false positives, maintenance, and re-execution becomes required.

Network

Perhaps one of the most notable drawbacks of creating an automated end-to-end testing solution is the reliance on external dependencies, in our case for example, a live server environment. An extra flaky factor can be introduced when a test attempts to assert against or interact with UI that is reliant on server content which may arrive late, or not arrive at all.

Animation and interaction delays

Other flaky factors such as animations and interaction delays require consideration too. It’s not an uncommon sight when investigating failed tests to see that it was caused by an interaction or assertion that occurred when the app was not quite ready, for e.g. tapping while the element exists, but before it was hittable enough to register the tap.

These are just a couple examples of common flaky factors you may encounter when UI-Testing, but they aren’t the only factors. Things such as general assertion timings, test execution order and even bugs in the test framework can also introduce flakiness. However, a shared concept for a range of timing based flaky factors exists that can be utilised to better improve the reliability of tests, waiting.

A brief about XCTWaiter in XCTest

There are a few approaches available to wait in XCUITest, I will briefly talk about some of the more common approaches I have seen utilised.

XCUIElement.waitForExistence(timeout:) will wait explicitly to a given timeout, and return a boolean per the element’s existence property.

open class XCUIElement : NSObject, XCUIElementAttributes, XCUIElementTypeQueryProvider {    open func waitForExistence(timeout: TimeInterval) -> Bool}

How to use waitForExistence?

if app.buttons["identifier"].waitForExistence(timeout: 5) {
// do some stuff
}

Xcode 8.3 introduced the XCTWaiterclass, which expanded on the former and allows us to better handle wait results, and provided the ability to wait for multiple expectations.

open class XCTWaiter : NSObject {public init(delegate: XCTWaiterDelegate?)weak open var delegate: XCTWaiterDelegate?open var fulfilledExpectations: [XCTestExpectation] { get }open func wait(for expectations: [XCTestExpectation], timeout seconds: TimeInterval) -> XCTWaiter.Resultopen func wait(for expectations: [XCTestExpectation], timeout seconds: TimeInterval, enforceOrder enforceOrderOfFulfillment: Bool) -> XCTWaiter.Resultopen class func wait(for expectations: [XCTestExpectation], timeout seconds: TimeInterval) -> XCTWaiter.Resultopen class func wait(for expectations: [XCTestExpectation], timeout seconds: TimeInterval, enforceOrder enforceOrderOfFulfillment: Bool) -> XCTWaiter.Result}

How to use XCTWaiter?

let expectation = expectation(
for: NSPredicate(format: "exists == true"),
evaluatedWith: app.buttons["identifier"],
handler: .none
)

let result = XCTWaiter.wait(for: [expectation], timeout: 30.0)

XCTAssertEqual(result, .completed)

⚠️ AVOID USAGE OF SLEEP ⚠️

Conclusion

We love the readability, flexibility and reliability that such methods provide. This post is just one part of how we can achieve readable, reliable (flaky-free) and maintainable UI tests for the iOS platform.

Let me know — along with any questions, comments, or feedback that you might have on https://www.linkedin.com/in/nshthshah.

--

--