addUIInterruptionMonitor(withDescription:handler:) not working on iOS 10 or 9
Asked Answered
A

3

22

The following tests works fine on iOS 11. It dismisses the alert asking permissions to use the locations services and then zooms in in the map. On iOS 10 or 9, it does none of this and the test still succeeds

func testExample() {
    let app = XCUIApplication()

    var handled = false
    var appeared = false

    let token = addUIInterruptionMonitor(withDescription: "Location") { (alert) -> Bool in
        appeared = true
        let allow = alert.buttons["Allow"]
        if allow.exists {
            allow.tap()
            handled = true
            return true
        }

        return false
    }

    // Interruption won't happen without some kind of action.
    app.tap()

    removeUIInterruptionMonitor(token)
    XCTAssertTrue(appeared && handled)
}

Does anyone have an idea why and/or a workaround?

Here's a project where you can reproduce the issue: https://github.com/TitouanVanBelle/Map

Update

Xcode 9.3 Beta's Changelogs show the following

XCTest UI interruption monitors now work correctly on devices and simulators running iOS 10. (33278282)

Anatolic answered 21/7, 2017 at 3:8 Comment(0)
B
43
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") 

let allowBtn = springboard.buttons["Allow"]
if allowBtn.waitForExistence(timeout: 10) {
    allowBtn.tap()
}

Update .exists to .waitForExistence(timeout: 10), detail please check comments.

Beachlamar answered 26/10, 2017 at 9:52 Comment(6)
I can't believe this works :) thx! However, I'd rather access the button by index, otherwise it won't work in different iOS versions (the button titles changed in iOS 11)Pearce
Using addUIInteruptionMonitor() wasn't working to dismiss SFAuthenticationSession alerts, but this technique worked for us.Smythe
This worked for me for testing a tel: URL scheme. addUIInteruptionMonitor doesn't find the iOS-produced alert.Hoye
This didn't work out of the box for me. But as I replaced .exists with .waitForExistence(timeout: 10) it worked.Pachydermatous
@ChristianBeer thanks for sharing. Yes, we also have same problem. Seems like .exist return true before real UI show up on screen in latest Xcode. .waitForExistence did help in this situation.Beachlamar
I am strugling with this. Like I don't know where to add this line of code. Should it be just before we are about to show Alert or after the code which is supposed to show trigger AlertSuperiority
W
3

I had this problem and River2202's solution worked for me.

Note that this is not a fix to get the UIInterruptionMonitor to work, but a different way of dismissing the alert. You may as well remove the addUIInterruptionMonitor setup. You'll need to have the springboard.buttons["Allow"].exists test anywhere the permission alert could appear. If possible, force it to appear at an early stage of the testing so you don't need to worry about it again later.

Happily the springboard.buttons["Allow"].exists code still works in iOS 11, so you can have a single code path and not have to do one thing for iOS 10 and another for iOS 11.

Incidentally, I logged the base issue (that addUIInterruptionMonitor is not working pre-iOS 11) as a bug with Apple. It has been closed as a duplicate now, so I guess they acknowledge that it is a bug.

Whitefish answered 2/11, 2017 at 10:1 Comment(0)
B
2

I used the @River2202 solution and it works better than the interruption one. If you decide to use that, I strongly suggest that you use a waiter function. I created this one in order to wait on any kind of XCUIElement to appear:

Try it!

// function to wait for an ui element to appear on screen, with a default wait time of 20 seconds
// XCTWaiter was introduced after Xcode 8.3, which is handling better the timewait, it's not failing the test.  It uses an enum which returns: 'Waiters can be used with or without a delegate to respond to events such as completion, timeout, or invalid  expectation fulfilment.'
@discardableResult
func uiElementExists(for element: XCUIElement, timeout: TimeInterval = 20) -> Bool {
    let expectation = XCTNSPredicateExpectation(predicate: NSPredicate(format: "exists == true"), object: element)
    let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
    guard result == .completed else {
        return false
    }
    return true
}
Box answered 19/10, 2018 at 19:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.