Swift2 UI Test - Wait for Element to Appear

二次信任 提交于 2019-12-04 17:10:32

问题


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?


回答1:


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.




回答2:


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




回答3:


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()



回答4:


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.




回答5:


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.




回答6:


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)


来源:https://stackoverflow.com/questions/34047887/swift2-ui-test-wait-for-element-to-appear

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!