Mastering Permission Request Alerts in XCUITest

Lee young-jun
3 min readSep 16, 2023

--

During the development of the Siwonschool app, I made note of new insights I gained about XCUITest. I intend to revise and share these insights one by one.

You may see alerts like this if you launch the app for the first time.

When encountering an alert during UI testing, it can be challenging to interact with buttons on the screen.

Fortunately, Apple provides the addUIInterruptionMonitor method to address this issue.

let monitor = addUIInterruptionMonitor(withDescription: "Push Permission") { (alert) -> Bool in
alert.buttons["허용"].tap();

return true;
}

Initially, you might think that the withDescription parameter is used for triggering the handler, as in 'the handler will be triggered if the alert has the specified description.'

However, it's important to note that withDescription is primarily for logging purposes and doesn't control the triggering of the handler based on description.

To work around this, I had to check if the button’s name is ‘허용’ (which means ‘Agree’) on the alert.

Additionally, it’s crucial to remember to remove the interruption monitor after the handler is triggered; otherwise, the handler will be triggered whenever any alert is presented.”

self.removeUIInterruptionMonitor(monitor);

Otherwise, the handler will be triggered whenever any alert presented.

Advanced

Sleep

Kickgoing has a long splash screen, causing the testing process to finish before the alert buttons can be interacted with.

To address this issue, I appended Sleep.

let monitor = ...

sleep(5)

Touchable testID

TouchableHighlight has a testID, so I expected to be able to interact with it using the testID during testing.

<TouchableHighlight
testID="confirm"

However XCUITest couldn’t find the button with testID.

app.buttons["confirm"].tap();

To locate TouchableHighlight in XCUITest, I had to use otherElements instead of buttons.

app.otherElements["confirm"].tap();

Full Source

let app = XCUIApplication()
app.launch()

let permissionMonitor = addUIInterruptionMonitor(withDescription: "Permission") { (alert) -> Bool in
debugPrint("alert monitor begin")
let allowLocationButton = alert.buttons["앱을 사용하는 동안 허용"]

if allowLocationButton.exists {
debugPrint("tap allow always on alert")
allowLocationButton.tap();
return true
}

let allowButton = alert.buttons["허용"]

if allowButton.exists {
debugPrint("tap allow on alert")
allowButton.tap();
return true
}

return false
}

sleep(5)

app.otherElements["confirm"].tap();

app.tap()

self.removeUIInterruptionMonitor(permissionMonitor)

Now my UI testing can successfully handle all permission alerts.

Troubleshooting

addUIInterruptionMonitor is never called.

Do any gesture after presenting alert like this.

let monitor = ...

...

app.swipeUp()

References

--

--

No responses yet