Bartłomiej Semańczyk
Bartłomiej Semańczyk

Reputation: 61774

Handler of addUIInterruptionMonitor is not called for Alert related to Photos

private func acceptPermissionAlert() {
    
    _ = addUIInterruptionMonitor(withDescription: "") { alert -> Bool in
        
        if alert.buttons["Don’t Allow"].exists { //doesnt get here second time
            
            alert.buttons.element(boundBy: 1).tapWhenExists()
            
            return true
        }
        
        return false
    }
}

and this doesn't work for:

enter image description here

In the beginning of the app, it works perfect while accepting permission for notifications, but here, it doesn't work. Why is this?

Upvotes: 28

Views: 14342

Answers (4)

Ivan Vavilov
Ivan Vavilov

Reputation: 1649

In case the suggested solutions don't work on iOS 17+, I found a workaround. In this snippet I have 4 different permissions, one of them is location, which has a different button name.

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
for i in 0..<4 {
    let allowLocationButton = springboard.buttons["Allow While Using App"]
    let allowButton = springboard.buttons["Allow"]
            
    if allowLocationButton.isHittable {
        allowLocationButton.tap()
    } else if allowButton.isHittable {
        allowButton.tap()
    } else {
        break
    } 
}

Upvotes: 0

Taylor Lindsay
Taylor Lindsay

Reputation: 311

I'vs found that addUIInterruptionMonitor sometimes doesn't handle an alert in time, or until tests have finished. If it isn't working, try using Springboard, which manages the iOS home screen. You can access alerts, buttons, and more from there, and this is particularly useful for tests where you know exactly when an alert will show.

So, something like this:

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") 

let alertAllowButton = springboard.buttons.element(boundBy: 1)
if alertAllowButton.waitForExistence(timeout: 5) {
   alertAllowButton.tap()
}

The buttons.element(boundBy:1) will ensure you tap the button on the right, change 1 to 0 to tap the left, (because sometimes the ' in "Don't Allow" causes a problem).

Upvotes: 31

Bartłomiej Semańczyk
Bartłomiej Semańczyk

Reputation: 61774

Add:

app.tap()

at the end of the method.

This is because you need to interact with the app for the handler to fire.

Upvotes: 22

Oletha
Oletha

Reputation: 7639

After adding the interruption monitor, you should continue to interact with the app as if it has not appeared.

Also note that you have a 'smart quote' in your button identifier, instead of a regular apostrophe.

let photosAlertHandler = addUIInterruptionMonitor(withDescription: "Photo Permissions") { alert -> Bool in
    if alert.buttons["Don't Allow"].exists {
        alert.buttons.element(boundBy: 1).tapWhenExists()
        return true
    }
    return false
}

// Do whatever you want to do after dismissing the alert
let someButton = app.buttons["someButton"]
someButton.tap() // The interruption monitor's handler will be invoked if the alert is present

When the next interaction happens after the alert appears, the interruption monitor's handler will be invoked and the alert will be handled.

You should also remove the interruption monitor when you think you're done with it, otherwise it will be invoked for any other alerts that appear.

removeUIInterruptionMonitor(photosAlertHandler)

Upvotes: 13

Related Questions