I want to have a test pause and wait for an element to appear on screen before proceeding.
I don\'t see a good way to create an expectation for this and wait using
In expectationForPredicate(predicate: evaluatedWithObject: handler:)
you don't give an actual object, but a query to find it in the view hierarchy. So, for example, this is a valid test:
let predicate = NSPredicate(format: "exists == 1")
let query = XCUIApplication().buttons["Button"]
expectationForPredicate(predicate, evaluatedWithObject: query, handler: nil)
waitForExpectationsWithTimeout(3, handler: nil)
Check out UI Testing Cheat Sheet and documentation generated from the headers (there is no official documentation at the moment), all by Joe Masilotti.
Based on onmyway133 code I came up with to extensions (Swift 3.2):
extension XCTestCase {
func wait(for element: XCUIElement, timeout: TimeInterval) {
let p = NSPredicate(format: "exists == true")
let e = expectation(for: p, evaluatedWith: element, handler: nil)
wait(for: [e], timeout: timeout)
}
}
extension XCUIApplication {
func getElement(withIdentifier identifier: String) -> XCUIElement {
return otherElements[identifier]
}
}
So on your call site you can use:
wait(for: app.getElement(withIdentifier: "ViewController"), timeout: 10)
You can use this, in Swift 3
func wait(element: XCUIElement, duration: TimeInterval) {
let predicate = NSPredicate(format: "exists == true")
let _ = expectation(for: predicate, evaluatedWith: element, handler: nil)
// We use a buffer here to avoid flakiness with Timer on CI
waitForExpectations(timeout: duration + 0.5)
}
In Xcode 9, iOS 11, you can use the new API waitForExistence
This question was asked about Swift2 but it's still a top search result in 2019 so I wanted to give an up-to-date answer.
With Xcode 9.0+ things are a bit simpler thanks to waitForExistence:
let app = XCUIApplication()
let myButton = app.buttons["My Button"]
XCTAssertTrue(myButton.waitForExistence(timeout: 10))
sleep(1)
myButton.tap()
WebViews Example:
let app = XCUIApplication()
let webViewsQuery = app.webViews
let myButton = webViewsQuery.staticTexts["My Button"]
XCTAssertTrue(myButton.waitForExistence(timeout: 10))
sleep(1)
myButton.tap()
For Xcode 8.3 and later you can wait for expectation with a new class - XCTWaiter
, an example test looks like this:
func testExample() {
let element = // ...
let predicate = NSPredicate(format: "exists == true")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
let result = XCTWaiter().wait(for: [expectation], timeout: 1)
XCTAssertEqual(.completed, result)
}
Read the documentation for more information.
It doesn't take an already existing element. You just need to define the following predicate:
let exists = NSPredicate(format: "exists = 1")
Then just use this predicate in your expectation. Then of course wait on your expectation.