Thursday, 30 July 2020

Xcode UI tests: saveScreenshot(...) extension function

Taking a screenshot as part of an Xcode UI test and adding the screenshot to the test's output is a five-step shuffle as follows:

let screenshot = XCUIApplication().screenshot()
let attachment = XCTAttachment(screenshot: screenshot)
attachment.lifetime = .keepAlways = "SomeName"

Wouldn't it be great if this could be reduced to a single line call as follows:

XCUIApplication().saveScreenshot(to: self, named: "SomeName")

To make this possible, all you need to do is add the following extension function to your UI testing bundle:

extension XCUIScreenshotProviding {
    func saveScreenshot(to activity: XCTActivity, named name: String) {
        let attachment = XCTAttachment(screenshot: screenshot())
        attachment.lifetime = .keepAlways = name
You can find this extension function and others like it in the XCTestExtensions repo.

Saturday, 25 July 2020

Xcode UI tests: waitForNonExistence(...) extension function

The XCUIElement.waitForExistence(timeout:) function is great for waiting on an element to appear whilst an animation or asynchronous operation completes. However, there's equally a need at times to wait for an element to disappear and, sadly, XCUIElement does not offer such a function. Good news though! It turns out that it's not difficult at all to compose an extension function on XCUIElement which does exactly this, as follows:

extension XCUIElement {

     * Waits the specified amount of time for the element’s `exists` property to become `false`.
     * - Parameter timeout: The amount of time to wait.
     * - Returns: `false` if the timeout expires without the element coming out of existence.
    func waitForNonExistence(timeout: TimeInterval) -> Bool {

        let timeStart = Date().timeIntervalSince1970

        while (Date().timeIntervalSince1970 <= (timeStart + timeout)) {
            if !exists { return true }
        return false

You can find this extension function and others like it in the XCTestExtensions repo.