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

Xcode7 | Тесты интерфейса Xcode | Как справиться с оповещением о местоположении?

Я пишу тестовые примеры для одного из моих приложений, используя XCUIApplication, XCUIElement и XCUIElementQuery, представленные в Xcode7/iOS 9.

Я попал в дорожный блок. Один из экранов в тестовом случае требует службы местоположения iOS. Как и ожидалось, пользователю будет предложено разрешить использование службы определения местоположения с предупреждением под заголовком: Allow "App name" to access your location while you use the app? с кнопками Allow и Don't Allow.

Проблема в том, что, так как предупреждение представлено самой ОС, оно отсутствует в поддереве элемента приложения.

Я зарегистрировался следующим образом:

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

Даже запись в пользовательском интерфейсе сгенерировала аналогичный код:

XCUIApplication().alerts["Allow "App Name" to access your location while you use the app?"].collectionViews.buttons["Allow"].tap()

Я не нашел API, который может заставить меня пройти мимо этой проблемы. Например:

  • Нажмите в позиции на экране
  • Получить оповещения вне приложения

Итак, как я могу пройти мимо этого? Есть ли способ настроить тестовые цели, чтобы не разрешать авторизацию службы геопозиционирования.

4b9b3361

Ответ 1

Xcode 9

    let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
    let allowBtn = springboard.buttons["Allow"]
    if allowBtn.exists {
        allowBtn.tap()
    }

Xcode 8.3.3

    _ = 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

Обратите внимание, что это немного отличается, поскольку имя метода теперь является addUIInterruptionMonitor и принимает в качестве аргумента withDescription

Xcode 7.1

Xcode 7.1 наконец исправил проблему с системными оповещениями. Есть, однако, две маленькие ошибки.

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

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

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

"Диалог местоположения" - это просто строка, помогающая разработчику определить, к какому обработчику обращались, она не относится к типу оповещения.

Xcode 7.0

Следующее отклонит единственное "системное предупреждение" в Xcode 7 Beta 6:

let app = XCUIApplication()
app.launch()
// trigger location permission dialog

app.alerts.element.collectionViews.buttons["Allow"].tap()

Бета 6 представила множество исправлений для UI Testing, и я считаю, что это был один из них.

Также обратите внимание, что я звоню -element прямо на -alerts. Вызов -element для XCUIElementQuery заставляет платформу выбрать "один-единственный" соответствующий элемент на экране. Это прекрасно работает для оповещений, когда вы можете видеть только одно изображение за раз. Однако, если вы попробуете это для метки и у вас будет две метки, фреймворк вызовет исключение.

Ответ 2

Это единственное, что сработало для меня. Использование Xcode 9 fwiw.

Также возможно, что я уже использовал addUIInterruptionMonitor для другого оповещения. Я попробовал переупорядочить их, и это не изменило ситуацию. Может быть, это проблема в 9, когда у вас есть две, или я могу использовать их неправильно. В любом случае код ниже работал.:)

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let allowBtn = springboard.buttons["Allow"]
if allowBtn.exists {
    allowBtn.tap()
}

Ответ 3

Если вы хотите проверить, отображается ли предупреждение, просто проверьте наличие кнопки:

if (app.alerts.element.collectionViews.buttons["Dismiss"].exists)
{
app.alerts.element.collectionViews.buttons["Dismiss"].tap()
}

он проверяет, отображается ли предупреждение, и если он показывает его, он коснется его

Ответ 4

Я заставил это работать с этим на Xcode 9.4.1, уловка состояла в том, чтобы ждать появления всплывающего окна.

// 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()
    }

Ответ 5

В xcode 9.1 предупреждения обрабатываются только в том случае, если тестовое устройство имеет iOS 11. Не работает на старых версиях iOS, например, 10.3 и т.д. Ссылка: https://forums.developer.apple.com/thread/86989

Для обработки предупреждений используйте это:

//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

Ответ 6

Это работает для всех языков:

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let allowBtn = springboard.buttons.element(boundBy: 1)
if allowBtn.exists {
    allowBtn.tap()
}

Ответ 7

Чтобы разрешить доступ к предупреждению о местоположении, вы можете позвонить element.tap(), где элемент - это любой элемент на вашем экране. Таким образом, после вызова нажмите, доступ будет нажать "Разрешить на предупреждение", а затем коснуться вашего элемента

Ответ 8

Вот что я сделал, чтобы принять уведомление о разрешении уведомлений на любом языке, нажав вторую кнопку в диалоговом окне (две кнопки). Кнопка "Разрешить" находится справа, поэтому индекс 1.

let handler = addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in
    alert.buttons.element(boundBy: 1).tap()
    return true
}
app.tap()