Reputation: 11253
We're using a UIAlertController
as a loading indicator while a network request occurs. There are no actions associated with this UIAlertController
as it is closed automatically when the network activity is completed. We display this alert after the user taps the login button for our app.
When we run our tests, they fail at the point right after this with:
UI Testing Failure - Did not receive view did disappear notification within 2.0s
Per other answers on SO, I've tried to use addUIInterruptionMonitor
to handle the alert, but without any success. I think this is because there are no actionable buttons on the UIAlertController
. Since there's no action that can be taken on the alert, the interruption monitor just looks like this:
addUIInterruptionMonitor(withDescription: "Loading") { handler in
return true
}
Even with this though, I get the same error. How can I work around this?
EDIT: Relevant UI testing code below:
class UI_Tests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = true
XCUIApplication().launch()
}
func testLogin() {
let app = XCUIApplication()
let tablesQuery = app.tables
let secureTextField = tablesQuery.cells.containing(.staticText, identifier:"PIN").children(matching: .secureTextField).element
secureTextField.tap()
secureTextField.typeText("1234")
app.buttons["Login"].tap()
addUIInterruptionMonitor(withDescription: "Loading") { handler in
return true
}
// Test failure occurs here.
let searchField = tablesQuery.searchFields.element(boundBy: 0)
searchField.tap()
searchField.typeText("hey")
}
}
Upvotes: 0
Views: 1211
Reputation: 11253
After reaching out to Apple DTS, it turns out that when displaying a UI interruption / UIAlertController
that dismisses based on a timeout, that you need to combine the UI interruption monitor with a timeout-based expectation (otherwise, the interruption monitor will return before the alert has dismissed!).
Using the UI testing example in the question, this approach looks like this:
class UI_Tests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = true
XCUIApplication().launch()
}
func testLogin() {
let app = XCUIApplication()
let tablesQuery = app.tables
let secureTextField = tablesQuery.cells.containing(.staticText, identifier:"PIN").children(matching: .secureTextField).element
secureTextField.tap()
secureTextField.typeText("1234")
app.buttons["Login"].tap()
addUIInterruptionMonitor(withDescription: "Loading") { alert in
self.expectation(for: NSPredicate(format: "exists == false"), evaluatedWith: alert, handler: nil);
self.waitForExpectations(timeout: 10, handler: nil)
return true
}
// Test failure occurs here.
let searchField = tablesQuery.searchFields.element(boundBy: 0)
searchField.tap()
searchField.typeText("hey")
}
}
This expectation will wait for 10 seconds to be filled. If the alert doesn't dismiss after 10 seconds, the expectation won't be met and the test will fail, but if it does, the test will succeed.
Upvotes: 1