Подтвердить что ты не робот

Тестирование пользовательского интерфейса Xcode 7: отклонение предупреждений Push и Location

Я столкнулся с проблемой тестирования Xcode 7 UI.

Приложение отображает два предупреждения после моего входа в систему, оповещение Запрос местоположения и предупреждение Push Notifications. Эти уведомления показаны один за другим. Сначала будет показано местоположение.

Я пытаюсь автоматически их отклонить, чтобы начать тесты.

Чтобы сделать это, я добавлю два UIInterruptionMonitor, первый для оповещения о местоположении и второй для оповещения Push Push.

    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
    }

Но запускается только одно местоположение, обработчик Push Notifications UIInterruptionMonitor никогда не вызывается.

Если я верю true в Request Location UIInterruptionMonitor как этот другой принятый ответ. Оба обработчика вызываются, но параметр предупреждения в обоих UIInterruptionMonitor ссылается на представление Request Location Alert View, поэтому кнопка "OK" никогда не будет найдена.

Как я могу уволить эти два последующих просмотра предупреждений?

4b9b3361

Ответ 1

В то время как я не был идеальным, я обнаружил, что если вы просто дождитесь завершения одного диалога авторизации перед представлением другого в приложении, тесты пользовательского интерфейса могут отображать несколько запросов в строке.

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

Я действительно запрашиваю доступ к контактам в другом месте в своем коде, но он может обрабатывать несколько одновременных запросов просто отлично.

Тогда в моем тесте:

    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

Ответ 2

Как я отметил в ответе, о котором вы говорили, вы должны взаимодействовать с приложением после появления предупреждения.

Во-вторых, после представления предупреждения вы должны взаимодействовать с интерфейсом. Просто прослушивание приложения работает отлично, но это необходимо.

// add UI interruption handlers

app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire

Ответ 3

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: проверьте правильность оповещения, нажмите кнопку и найдите способ удаления монитора (я использую NotificationCenter)

2: Если вы введете монитор и не можете найти нужную кнопку, это означает, что это непредвиденный поток. Не удалось выполнить проверку (но сначала сделайте снимок экрана).

3: Добавить другие мониторы

4: Я добавляю монитор даже перед запуском приложения. Если вы добавите монитор после появления предупреждения, он не будет запущен.

5: Удалите монитор, таким образом, когда появится новое предупреждение, будет вызываться следующий монитор в стеке.

P.S: Вы должны добавить мониторы в обратном порядке, поэтому добавьте "Местоположение запроса" после "Push Notifications"

Ответ 4

Чтобы отклонить представления системного предупреждения (т.е. Push Notification), определить пользовательские флаги для среды тестирования.

Затем вам просто нужно изменить код приложения, чтобы избежать определенных инициализаций (например: Push Notification):

#if !TESTING
let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
#endif

Я использую этот трюк, чтобы иметь возможность делать скриншоты с snapshot.