Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift2 UI Test - Wait for Element to Appear

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

public func waitForExpectationsWithTimeout(timeout: NSTimeInterval, handler: XCWaitCompletionHandler?)

The method to create an expectation I have been using has been

public func expectationForPredicate(predicate: NSPredicate, evaluatedWithObject object: AnyObject, handler: XCPredicateExpectationHandler?) -> XCTestExpectation

But this takes an already existing element, whereas I would like to have the test wait for an element that does not yet exist.

Does anyone know the best way to do this?

like image 228
Alex Avatar asked Dec 02 '15 16:12

Alex


4 Answers

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.

like image 60
Tomasz Bąk Avatar answered Nov 09 '22 06:11

Tomasz Bąk


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()
like image 24
alanning Avatar answered Nov 09 '22 05:11

alanning


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

like image 5
onmyway133 Avatar answered Nov 09 '22 04:11

onmyway133


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.

like image 1
sylvanaar Avatar answered Nov 09 '22 05:11

sylvanaar