简体   繁体   English

Xcode 7 UI测试:解除推送和位置警报

[英]Xcode 7 UI Testing: Dismiss Push and Location alerts

I encountered a problem with Xcode 7 UI Testing. 我遇到了Xcode 7 UI测试的问题。

The app displays two alerts after my user logs in, the Request Location Alert and the Push Notifications Alert. 我的用户登录后,应用程序会显示两个警报,即请求位置警报和推送通知警报。 Those notifications are shown one right after the other. 这些通知一个接一个地显示。 The Location one appears first. 位置一出现在第一位。

I try to dismiss them automatically to start my tests. 我尝试自动解雇它们以开始我的测试。

In order to do that, I add two UIInterruptionMonitor , the first one for the Location Alert and the second one for the Notification Push Alert. 为此,我添加了两个UIInterruptionMonitor ,第一个用于Location Alert,第二个用于Notification Push Alert。

    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
    }

But only the Location one is triggered, the handler of Push Notifications UIInterruptionMonitor is never called. 但只触发Location 1,从不调用Push Notifications UIInterruptionMonitor的处理程序。

If I return true in the Request Location UIInterruptionMonitor as this other post accepted answer specifies. 如果我在请求位置 UIInterruptionMonitor中返回true,则此其他帖子接受的答案指定。 Both handler are called but the alert parameter in both UIInterruptionMonitor links to the Request Location Alert View so the "OK" button is never found. 两个处理程序都被调用,但两个UIInterruptionMonitor中alert参数都链接到请求位置警报视图,因此永远找不到“确定”按钮。

How can I dismiss those two successive alerts views? 如何解除这两个连续的警报视图?

While not ideal, I found that if you simply wait until one authorization dialog has finished before presenting another one in the app, UI tests can pick up multiple requests in a row. 虽然不理想,但我发现如果您只是等到一个授权对话框完成后再在应用程序中显示另一个授权对话框,则UI测试可以连续获取多个请求。

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

I'm actually requesting access to contacts in a different place in my code, but it can handle multiple simultaneous requests just fine. 我实际上是在我的代码中请求访问不同位置的联系人,但它可以处理多个同时请求。

Then in my 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

As I noted in the answer you mentioned , you must interact with the application after the alert appears. 正如我在您提到的答案中所述 ,您必须在警报出现后与应用程序进行交互。

Second, after presenting the alert you must interact with the interface. 其次,在显示警报后,您必须与界面进行交互。 Simply tapping the app works just fine, but is required. 只需点击应用程序就可以正常工作,但这是必需的。

// add UI interruption handlers

app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire
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: Check if you're in the correct alert, tap the button and find a way to remove the monitor (I'm using NotificationCenter) 1:检查您是否处于正确的警报状态,点击按钮并找到删除显示器的方法(我正在使用NotificationCenter)

2: If you enter a monitor and can not find the right button, it means it's an unexpected flow. 2:如果您进入监视器但找不到正确的按钮,则表示这是一个意外的流程。 Fail the test (but take a screenshot first). 测试失败(但先截取屏幕截图)。

3: Add other monitors 3:添加其他监视器

4: I am adding monitor even before launching the app. 4:我甚至在启动应用程序之前添加了监视器。 If you add a monitor after the alert appears, it will not be triggered. 如果在警报出现后添加监视器,则不会触发它。

5: Remove the monitor, that way when a new alert appears, the next monitor in the stack will be called. 5:删除监视器,当出现新警报时,将调用堆栈中的下一个监视器。

PS: You should add monitors in reverse order, therefore, add "Request Location" after "Push Notifications" PS:您应该以相反的顺序添加监视器,因此,在“推送通知”之后添加“请求位置”

To dismiss system alert views (ie: Push Notification ) you can define custom flags for the testing environment . 要关闭系统警报视图(即: 推送通知 ),您可以为测试环境定义自定义标志

Then, you just have to change the application's code to avoid specific initialisations (ie: Push Notification ) : 然后,您只需更改应用程序的代码以避免特定的初始化(即: 推送通知 ):

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

I use this trick in order to be able to take screenshots with snapshot . 我使用这个技巧,以便能够截取快照截图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM