So recently Apple introduced this prompt: “XXXX” Wants to Use “auth0.com” to Sign In Where “XXXX” is the ios app name.
This alert/dialog comes up when in the case of Auth0 the user clicks on “Login with Google” or “Login with Facebook”. That’s all nice but when running IOS UI tests, this dialog doesn’t go away when using the usual way of dismissing system dialogs:
func doUserLogin(_ app: XCUIApplication) {
app.staticTexts["notLoggedInActivelabel"].tap()
// this will bring up oauth0 login window in ios
// setup a handler to dismiss the system alert
let handler = self.addUIInterruptionMonitor (withDescription: "allow oauth") { (alert) -> Bool in
// code should come here where the dialog is presented,
// but it never does ....
alert.buttons["Continue"].tap() // click Continue Button
return true
}
// click the login with GOOGLE button. This brings up dialog “XXXX” Wants to Use “auth0.com” to Login
app.scrollViews.otherElements.buttons["LOG IN WITH GOOGLE"].tap()
// this step is required when using addUIInterruptionMonitor
app.tap()
removeUIInterruptionMonitor(handler)
}
It kinda makes sense to me: This is a security system dialog introduced by Apple in order to improve security. Having it easily dismissed in the code would defeat the purpose.
But still, anyone knows if it's possible to dismiss this dialog in an XCTestCase?
I think Apple expects from a developer to make use of the introduced addUIInterruptionMonitor.
In fact, the addUIInterruptionMonitor(withDescription: )
is not working, so I went down the road to access the Springboard and select the appropriate permission on the system alert.
1. Extended the XCTestCase to reuse this function, if necessary
extension XCTestCase {
// I hope this code is mostly reusable
// I didn't test it for Location Permission While in Use vs. Always...
func setPermission(for alert:XCUIElement, allow: Bool) -> Bool {
if alert.elementType == .alert {
// make sure to support any language
// Might also be "allow" for some dialogs
let buttonIdentifier = allow ? "Continue" : "Cancel"
let identifierButton = alert.buttons[buttonIdentifier]
if identifierButton.exists && identifierButton.isHittable {
identifierButton.tap()
return true
}
// Or, if you don't want to bother with the language/identifiers
// Allow = Last button Index (probably 1), Cancel = 0
let buttonIndex = allow ? alert.buttons.count - 1 : 0
let indexButton = alert.buttons.element(boundBy: buttonIndex)
if indexButton.exists && indexButton.isHittable {
indexButton.tap()
return true
}
}
return false
}
}
2. Call this function in your test like
// This holds a reference to your SignIn/Login XCUIElement
yourSignInButton.tap()
let systemAlerts = XCUIApplication(bundleIdentifier: "com.apple.springboard").alerts
if systemAlerts.count > 0 {
_ = self.setPermission(for: systemAlerts.element(boundBy: 0), allow: true)
}
Optional: Springboard Class
I also created a Springboard Class, as I have also System Settings tests etc. running...
class Springboard {
static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
}
This way, you could call your XCUITestCase
extension the following way:
let systemAlerts = Springboard.springboard.alerts
if systemAlerts.count > 0 {
self.setPermission(for: systemAlerts.element(boundBy: 0), allow: true)
}
If, the addUIInterruptionMonitor(withDescription: )
was actually working, this could then look like the following:
Caution: currently, only working for Authorization/Permission alerts of Location, Microphone, etc.
let interruptionMonitor = addUIInterruptionMonitor(withDescription: "Allow the app and website to share information") { (alert) -> Bool in
return self.setPermission(for: systemAlerts.element(boundBy: 0), allow: true)
}
// This holds a reference to your SignIn/Login XCUIElement
yourSignInButton.tap()
removeUIInterruptionMonitor(interruptionMonitor)