XCode 7 UI Testing: Dismissal of system-generated

2019-02-19 12:23发布

问题:

I have a UI test which involves the dismissal of a system-generated UIAlertController. This alert asks the user for the permission to access the device's calendar. The objective of the test is the behaviour after a tap on the OK button:

1 let app = XCUIApplication()
...
// this code was basically generated by the recording feature of XCode 7 
2 app.alerts.elementBoundByIndex(0).collectionViews.buttons["OK"].tap()

Now, instead of clicking the OK button, line 2 makes the simulator tap onto the first button which happens to be the Cancel button...

Additionally, I found out that the testing framework does not accurately recognize the appearing alert. So if I check the current count of alerts I always get 0:

// ...tap...
let count = app.alerts.count // == 0

This also happens if I use an NSPredicate for the condition and wait for several seconds.

Is it possible that UI tests do not work reliably with system-generated alerts? I am using XCode 7.0.1.

回答1:

Xcode 7.1 has finally fixed the issue with system alerts. There are, however, two small gotchas.

First, you need to set up a "UI Interuption Handler" before presenting the alert. This is our way of telling the framework how to handle an alert when it appears.

Second, after presenting the alert you must interact with the interface. Simply tapping the app works just fine, but is required.

addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
    alert.buttons["Allow"].tap()
    return true
}

app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire

The "Location Dialog" is just a string to help the developer identify which handler was accessed, it is not specific to the type of alert. I believe that returning true from the handler marks it as "complete", which means it won't be called again.



回答2:

I managed to dismiss access prompt for contacts like this:

let alert = app.alerts["\u{201c}******\u{201d} Would Like to Access Your Contacts"].collectionViews.buttons["OK"]
if alert.exists
{
    alert.tap()
}

Replace asterisks with your app's name. It might work the same for calendar.

This is what I ended up using to get the prompt to appear and then allow access to Contacts:

func allowAccessToContacts(textFieldsName: String)
{
    let app = XCUIApplication()

    let textField = app.textFields[textFieldsName]
    textField.tap()
    textField.typeText("aaa")

    let alert = app.alerts["\u{201c}******\u{201d} Would Like to Access Your Contacts"].collectionViews.buttons["OK"]
    if alert.exists
    {
        alert.tap()
    }
    textField.typeText("\u{8}\u{8}\u{8}")
}