How to check for the presence of static text displayed from the network in UI tests in Xcode?
Asked Answered
G

4

19

I am using the UI test APIs introduced in Xcode 7 XCTest. On my screen I have a text that is loaded from the network.

The test fails if I simply check it with exists property.

XCTAssert(app.staticTexts["Text from the network"].exists) // fails

It does work though if I first send the tap or any other event to the text like this:

app.staticTexts["Text from the network"].tap()
XCTAssert(app.staticTexts["Text from the network"].exists) // works

It looks like if I just call exists it evaluates it immediately and fails because the text has not been downloaded from the network yet. But I think when I call the tap() method it waits for the text to appear.

Is there a better way to check for the presence of a text that is delivered from the network?

Something like (this code will not work):

XCTAssert(app.staticTexts["Text from the network"].eventuallyExists)
Garfish answered 7/7, 2015 at 6:27 Comment(1)
I updated my answer for Xcode 7 Beta 4. Since it drastically changes the accepted answer I wanted to let you know.Sarnen
S
29

Xcode 7 Beta 4 added native support for asynchronous events. Here's a quick example of how to wait for a UILabel to appear.

XCUIElement *label = self.app.staticTexts[@"Hello, world!"];
NSPredicate *exists = [NSPredicate predicateWithFormat:@"exists == 1"];

[self expectationForPredicate:exists evaluatedWithObject:label handler:nil];
[self waitForExpectationsWithTimeout:5 handler:nil];

First create a query to wait for a label with text "Hello, world!" to appear. The predicate matches when the element exists (element.exists == YES). Then pass the predicate in and evaluate it against the label.

If five seconds pass before the expectation is met then the test will fail. You can also attach a handler block in that gets called when the expectation fails or times out.

If you're looking for more information regarding UI Testing in general, check out UI Testing in Xcode 7.

Sarnen answered 15/7, 2015 at 11:47 Comment(0)
S
1

XCode9 has a method waitForExistence(timeout: TimeInterval) of XCUIElement

extension XCUIElement {
    // A method for tap element
    @discardableResult
    func waitAndTap() -> Bool {
        let _ = self.waitForExistence(timeout: 10)
        let b = self.exists && self.isHittable
        if (b) {
            self.tap()
        }
        return b
    }
}

// Ex:
if (btnConfig.waitAndTap() == true) {
    // Continue UI automation
} else {
    // `btnConfig` is not exist or not hittable.
}

But I encounter another problem, the element is exist, but not hittable. So I extend a method to wait an element to be hittable.

extension XCTestCase {
    /// Wait for XCUIElement is hittable.
    func waitHittable(element: XCUIElement, timeout: TimeInterval = 30) {
        let predicate = NSPredicate(format: "isHittable == 1")
        expectation(for: predicate, evaluatedWith: element, handler: nil)
        waitForExpectations(timeout: timeout, handler: nil)
    }
}

// Ex:
// waitHittable(element: btnConfig)
Sainthood answered 4/1, 2018 at 7:10 Comment(0)
B
0

If I'm right in understanding you that the target text has already displayed when you're checking it's existing, you can try to use hittable property.

Bouncing answered 8/12, 2016 at 10:10 Comment(0)
P
0

Swift 3:

let predicate = NSPredicate(format: "exists == 1")
let query = app!.staticTexts["identifier"]
expectation(for: predicate, evaluatedWith: query, handler: nil)
waitForExpectations(timeout: 5, handler: nil)

It will continuously check for 5 seconds whether that text is displayed or not.

As soon as it will find the text may be in less than 5 seconds, it will execute further code.

Protractor answered 4/8, 2017 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.