narner
narner

Reputation: 3241

Xcode UI Unit Tests and Permission Alerts

I'm working on a UI unit test for my app, and am trying to figure out how to automatically have the test framework click "OK" when the system presents an alert asking for permission to access contacts.

So far, I've looked at these four SO posts, and tried the various suggestions, but am still unable to get this to work:

XCTest app tests and permissions alerts

Xcode 7 UI Testing: how to dismiss a series of system alerts in code

Xcode UI Testing allow system alerts series

Xcode 7 UI Testing: Dismiss Push and Location alerts

Here's what I currently am trying - however, the permissions dialog is still not being automatically accepted; the test waits for me to click "OK" before moving forward: func testApp() {

    self.addUIInterruptionMonitor(withDescription: "MyDescription", handler: { (alert) -> Bool in
        let button = alert.buttons["OK"]
        if button.exists {
            button.tap()
            return true
        }
        return false
    })

    let app = XCUIApplication()
    app.launch()
    ...
    app.tap()
    ...
}

EDIT: Here's the change I've made based on @ad-johnson's suggestion:

var app: XCUIApplication!

override func setUp() {
    super.setUp()

    continueAfterFailure = false
    app = XCUIApplication()

    addUIInterruptionMonitor(withDescription: "Contact Auth")
    { (alert) -> Bool in if alert.buttons["OK"].exists {
        alert.buttons["OK"].tap()
        }
        return true }

    app.launch()
}


func testScreenshots() {
    app.tap()
    ...
}

Upvotes: 4

Views: 5376

Answers (2)

kelin
kelin

Reputation: 12011

I tried addUIInterruptionMonitor many times and it never works. Access directly to the button through the Sprignboard app proxy:

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let okBtn = springboard.buttons["OK"]
if okBtn.waitForExistence(timeout: 1.5) {
    okBtn.tap()
}

Upvotes: 0

ad-johnson
ad-johnson

Reputation: 565

May not be too helpful, but this matches what I have (for allowing access to Location Services, so I wait for an "Allow" button.) The only difference is that the order I have is 1) let app= 2) add the monitor 3) launch app. All in setup(). The app.tap is in the func testApp(). XCUIApplication() creates a new instance of the app each time it is called: I think I'd try moving that before the monitor in the first instance. Here's my setup method (ignore the UITestHelper call):

override func setUp() {
    super.setUp()

    continueAfterFailure = false
    app = XCUIApplication()

    // ensure app is currently authorised.  If the first install is to
    // happen then the settings won't exist yet but that's ok, the test
    // will handle the Location Services prompt and allow.
    UITestHelper.resetAuthorisation(setToInUse: true)

    addUIInterruptionMonitor(withDescription: "Location Services")
    { (alert) -> Bool in if alert.buttons["Allow"].exists {
        alert.buttons["Allow"].tap()
        }
        return true }

    app.launch()
}

and my test:

func testDoesNotAlertReminderIfAuthorised() {

    // given

    // When
    app.tap()
 ....

Upvotes: 2

Related Questions