J'écris des scénarios de test d'interface utilisateur pour l'une de mes applications à l'aide des applications XCUIApplication, XCUIElement et XCUIElementQuery introduites dans Xcode7/iOS 9.
J'ai frappé un barrage routier. L'un des écrans du scénario de test nécessite les services de localisation d'iOS. Comme prévu, l'utilisateur est invité à autoriser l'utilisation du service de localisation avec l'alerte intitulée: Allow “App name” to access your location while you use the app?
avec les boutons Allow
& Don't Allow
.
Le problème est ou si, il semble que puisque l'alerte est présentée par le système d'exploitation lui-même, elle n'est pas présente dans le sous-arbre d'éléments d'Application.
Je me suis connecté après:
print("XYZ:\(app.alerts.count)")//0
var existence = app.staticTexts["Allow “App Name” to access your location while you use the app?"].exists
print("XYZ:\(existence)")//false
existence = app.buttons["Allow"].exists
print("XYZ:\(existence)") //false
Même l'enregistrement de l'interface utilisateur a généré un code similaire:
XCUIApplication().alerts["Allow “App Name” to access your location while you use the app?"].collectionViews.buttons["Allow"].tap()
Je n'ai trouvé aucune API capable de résoudre ce problème. Par exemple:
Alors, comment puis-je surmonter ça? Existe-t-il un moyen de configurer les cibles de test pour que l'autorisation de service de localisation ne soit pas requise.
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons["Allow"]
if allowBtn.exists {
allowBtn.tap()
}
_ = addUIInterruptionMonitor(withDescription: "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
Notez que c'est un peu différent car le nom de la méthode est maintenant addUIInterruptionMonitor et prend withDescription en argument.
Xcode 7.1 a finalement résolu un problème d'alertes système. Il y a cependant deux petites prises.
Tout d'abord, vous devez configurer un "Gestionnaire d'interruption d'interface utilisateur" avant de présenter l'alerte. C’est notre manière de dire au framework comment gérer une alerte quand elle apparaît.
Deuxièmement, après avoir présenté l'alerte, vous devez interagir avec l'interface. Il suffit de taper sur l'application, mais cela est nécessaire.
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
Le "dialogue de localisation" est simplement une chaîne destinée à aider le développeur à identifier le gestionnaire auquel il a accédé. Elle n'est pas spécifique au type d'alerte.
Les éléments suivants ignoreront une seule "alerte système" dans Xcode 7 Beta 6:
let app = XCUIApplication()
app.launch()
// trigger location permission dialog
app.alerts.element.collectionViews.buttons["Allow"].tap()
La bêta 6 a introduit une série de correctifs pour les tests d'interface utilisateur et je crois que c'était l'un d'entre eux.
Notez également que j'appelle -element
directement sur -alerts
. L'appel de -element
sur une XCUIElementQuery
oblige la structure à choisir le "seul et unique" élément correspondant à l'écran. Cela fonctionne très bien pour les alertes dans lesquelles vous ne pouvez avoir qu'une seule visibilité à la fois. Cependant, si vous essayez ceci pour une étiquette et que vous avez deux étiquettes, la structure générera une exception.
C'était la seule chose qui a fonctionné pour moi. Utilisation de Xcode 9 fwiw.
Aussi probablement que je utilisais déjà addUIInterruptionMonitor
pour une alerte différente. J'ai essayé de les réorganiser et cela n'a pas fait de différence. Peut-être que c'est un problème lorsque vous en avez deux ou peut-être que je les utilisais mal. En tout état de cause, le code ci-dessous a fonctionné. :)
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons["Allow"]
if allowBtn.exists {
allowBtn.tap()
}
Si vous voulez vérifier si l'alerte est affichée, vérifiez simplement l'existence du bouton:
if (app.alerts.element.collectionViews.buttons["Dismiss"].exists)
{
app.alerts.element.collectionViews.buttons["Dismiss"].tap()
}
il vérifie si l'alerte est affichée et si elle est affichée, elle la tapera
Je l’ai fait fonctionner avec ceci sur Xcode 9.4.1 , l’astuce consistait à attendre que le popup apparaisse.
// wait for location service popup to appear
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons["Allow"]
expectation(for: NSPredicate(format: "exists == true"), evaluatedWith: allowBtn, handler: nil)
waitForExpectations(timeout: 10, handler: nil)
//allow location service
if allowBtn.exists {
allowBtn.tap()
}
Sur xcode 9.1, les alertes ne sont traitées que si le périphérique de test dispose d'iOS 11. Ne fonctionne pas sur les anciennes versions iOS, par exemple 10.3, etc. Référence: https://forums.developer.Apple.com/thread/86989
Pour gérer les alertes, utilisez ceci:
//Use this before the alerts appear. I am doing it before app.launch()
let allowButtonPredicate = NSPredicate(format: "label == 'Always Allow' || label == 'Allow'")
//1st alert
_ = addUIInterruptionMonitor(withDescription: "Allow to access your location?") { (alert) -> Bool in
let alwaysAllowButton = alert.buttons.matching(allowButtonPredicate).element.firstMatch
if alwaysAllowButton.exists {
alwaysAllowButton.tap()
return true
}
return false
}
//Copy paste if there are more than one alerts to handle in the app
Cela fonctionne pour toutes les langues:
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons.element(boundBy: 2)
if allowBtn.exists {
allowBtn.tap()
}
Pour taper sur autoriser l'alerte de lieu, vous pouvez appeler Element.tap () où élément est un élément de votre écran. Ainsi, après avoir appelé, appuyez sur Access, appuyez sur Autoriser en alerte, puis appuyez sur votre élément.