Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for all HTTP requests to finish in XCode UI tests?

Is there a way to wait for all network requests to finish when testing UI in XCode?

I have an app that sends HTTP requests to get some data from a server, and, in UI tests, I'd like to wait for this data to be retrieved before continuing. Currently I'm using sleep(1) but this approach doesn't seem reliable.

like image 219
Jeiwan Avatar asked Mar 31 '16 02:03

Jeiwan


People also ask

How do I run all test cases in XCode?

⌘U will build and run all your test cases. It is the most commonly used shortcut when creating unit test cases. It is equivalent to ⌘R (build & run) while doing app development. You can use this shortcut to build your test target and run all the test cases in your test target.

How do I test UI in XCode?

How to Run XCUI Tests on XCode. To run the XCUITests on XCode, you can click the highlighted icon below to see your newly created UI Test targets. You can hover on the “testExample()” test case and click the “Play” icon to run that specific test to see if everything was set up properly.

What is XCTest XCUITest?

XCTest and XCUITest are integrated with XCode and support writing of test suites with subclasses, methods, and assertions. Tests are run directly from Xcode and are written with either Swift or Objective C.

How do I run XCTest?

To run your app's XCTests on Test Lab devices, build it for testing on a Generic iOS Device: From the device dropdown at the top of your Xcode workspace window, select Generic iOS Device. In the macOS menu bar, select Product > Build For > Testing.


2 Answers

Your best bet is to wait for some UI element to appear or disappear. Think of it this way:

The framework acts like a user. It doesn't care what code is running under the hood. The only thing that matters is what is visible on the screen.

That said, here is how you can wait for a label titled "Go!" to appear in your UI Tests.

let app = XCUIApplication()
let goLabel = self.app.staticTexts["Go!"]
XCTAssertFalse(goLabel.exists)

let exists = NSPredicate(format: "exists == true")
expectationForPredicate(exists, evaluatedWithObject: goLabel, handler: nil)

app.buttons["Ready, set..."].tap()
waitForExpectationsWithTimeout(5, handler: nil)
XCTAssert(goLabel.exists)

You could also extract that into a helper method. If you use some Swift compiler magic you can even get the failure message to occur on the line that called the method.

private fund waitForElementToAppear(element: XCUIElement, file: String = #file, line: UInt = #line) {
    let existsPredicate = NSPredicate(format: "exists == true")
    expectationForPredicate(existsPredicate, evaluatedWithObject: element, handler: nil)

    waitForExpectationsWithTimeout(5) { (error) -> Void in
        if (error != nil) {
            let message = "Failed to find \(element) after 5 seconds."
            self.recordFailureWithDescription(message, inFile: file, atLine: line, expected: true)
        }
    }
}
like image 71
Joe Masilotti Avatar answered Oct 05 '22 13:10

Joe Masilotti


You can set up your methods with delegates or completion blocks, and in your test cases use a XCTestExpectation which you can fulfill when the data has been returned.

like image 44
pbush25 Avatar answered Oct 05 '22 13:10

pbush25