web-dev-qa-db-fra.com

Test de l'interface utilisateur Xcode 7: désactivation des alertes Push et de localisation

J'ai rencontré un problème avec Xcode 7 UI Testing.

L'application affiche deux alertes après la connexion de mon utilisateur, l'alerte Request Location et l'alerte Push Notifications. Ces notifications sont affichées l'une après l'autre. L'emplacement un apparaît en premier.

J'essaie de les renvoyer automatiquement pour commencer mes tests.

Pour ce faire, j'ajoute deux UIInterruptionMonitor, le premier pour l'alerte de localisation et le second pour l'alerte de notification.

    addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
        /* Dismiss Location Dialog */
        if alert.collectionViews.buttons["Allow"].exists {
            alert.collectionViews.buttons["Allow"].tap()
            return true
        }
        return false
    }
    addUIInterruptionMonitorWithDescription("Push Dialog") { (alert) -> Bool in
        /* Dismiss Push Dialog */
        if alert.collectionViews.buttons["OK"].exists {
            alert.collectionViews.buttons["OK"].tap()
            return true
        }
        return false
    }

Mais seul le Location one est déclenché, le gestionnaire de Push Notifications UIInterruptionMonitor _ n'est jamais appelé.

Si je retourne true dans Request Location _ ​​UIInterruptionMonitor comme cette autre réponse acceptée spécifie. Les deux gestionnaires sont appelés, mais le paramètre alert dans les deux UIInterruptionMonitor est lié à la vue d'alerte Request Location afin que le bouton "OK" ne soit jamais trouvé.

Comment puis-je rejeter ces deux vues d'alertes successives?

28
Thomas LEVY

Bien que cela ne soit pas idéal, j’ai constaté que si vous attendez simplement qu’une boîte de dialogue d’autorisation soit terminée avant d’en présenter une autre dans l’application, les tests d’interface utilisateur peuvent collecter plusieurs demandes à la suite.

    if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse || CLLocationManager.authorizationStatus() == .AuthorizedAlways {
        self.locationManager.requestLocation()
    } else {
        self.contactStore.requestAccessForEntityType(.Contacts) { _ in
            self.locationManager.requestWhenInUseAuthorization()
        }
    }

En fait, je demande l’accès à des contacts situés à un endroit différent de mon code, mais cela permet de gérer plusieurs demandes simultanées sans problème.

Puis dans mon test:

    addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
        let button = alert.buttons["Allow"]
        if button.exists {
            button.tap()
            return true
        }
        return false
    }
    addUIInterruptionMonitorWithDescription("Contacts Dialog") { (alert) -> Bool in
        let button = alert.buttons["OK"]
        if button.exists {
            button.tap()
            return true
        }
        return false
    }

    app.buttons["Location"].tap()

    app.tap() // need to interact with the app for the handler to fire
    app.tap() // need to interact with the app for the handler to fire
9
David Beck

Comme je l'ai noté dans la réponse que vous avez mentionnée , vous devez interagir avec l'application après l'apparition de l'alerte.

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.

// add UI interruption handlers

app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire
3
Joe Masilotti
class BaseTest: XCTestCase {
    let pushSent = NSNotification.Name.init("alert.pushSent")
    var notificationMonitor: NSObjectProtocol?

    override func setUp() {
        listenNotifications()
        let app = XCUIApplication()

        notificationMonitor = addUIInterruptionMonitor(withDescription: "Push Notifications") { [unowned self] (alert) -> Bool in
            let btnAllow = app.buttons["Allow"]
            //1:
            if btnAllow.exists {
                btnAllow.tap()
                NotificationCenter.default.post(name: self.pushSent, object: nil)
                return true
            }
            //2:
            //takeScreenshot
            XCTFail("Unexpected System Alert")
            return false
        }
        //3:
        //add code for "Request Location" monitor

        app.launchEnvironment = ["UITEST_DISABLE_ANIMATIONS" : "YES"]
        //4:
        app.launch()

    }

    func listenNotifications() {
        NotificationCenter.default.addObserver(forName: pushSent, object: nil, queue: nil) { (notification) in
            if let locationDialogHandeler = self.notificationMonitor {
                //5:
                self.removeUIInterruptionMonitor(locationDialogHandeler)
            }
        }
    }
}

1: Vérifiez si vous êtes dans la bonne alerte, appuyez sur le bouton et trouvez un moyen de retirer le moniteur (J'utilise NotificationCenter)

2: Si vous entrez dans un moniteur et que vous ne trouvez pas le bon bouton, cela signifie que le flux est inattendu. Échec du test (mais prenez d'abord une capture d'écran).

3: Ajouter d'autres moniteurs 

4: J'ajoute un moniteur avant même de lancer l'application. Si vous ajoutez un moniteur après l'apparition de l'alerte, celle-ci ne sera pas déclenchée.

5: retirez le moniteur. Ainsi, lorsqu'une nouvelle alerte apparaît, le moniteur suivant de la pile sera appelé.

P.S: Vous devez ajouter les moniteurs dans l’ordre inverse. Par conséquent, ajoutez «Emplacement de la demande» après «Notifications push».

0
Daniel Carlos