Xcode7 | Xcode UI 测试 | 如何处理定位服务警报?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31746225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 07:35:56  来源:igfitidea点击:

Xcode7 | Xcode UI Tests | How to handle location service alert?

xcodexctestios9xcode7-beta4xcode-ui-testing

提问by Taha Samad

I am writing UI Test Cases for one one of my app using the XCUIApplication, XCUIElement and XCUIElementQuery introduced in Xcode7/iOS 9.

我正在使用 Xcode7/iOS 9 中引入的 XCUIApplication、XCUIElement 和 XCUIElementQuery 为我的一个应用程序编写 UI 测试用例。

I have hit a road block. One of the screens in test case requires iOS's Location Services. As expected the user is prompted about allowing use of location service with alert titled: Allow “App name” to access your location while you use the app?with Allow& Don't Allowbuttons.

我遇到了障碍。测试用例中的屏幕之一需要 iOS 的定位服务。正如预期的那样,系统会提示用户允许使用带有标题为:Allow “App name” to access your location while you use the app?带有Allow&Don't Allow按钮的警报的位置服务。

Problem is or so it seems that since the alert is presented by OS itself it is not present in Application's element sub-tree.

问题是,似乎由于警报是由操作系统本身提供的,因此它不存在于应用程序的元素子树中。

I have logged following:

我记录了以下内容:

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

Even UI recording generated similar code:

甚至 UI 录制也生成了类似的代码:

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

I have not found any API that can get me past this problem. For example:

我还没有找到任何可以让我解决这个问题的 API。例如:

  • Tap at a position on the screen
  • Get alerts outside the app
  • 点击屏幕上的某个位置
  • 在应用程序外获取警报

So how can I get past this? Is there a way to configure Test Targets so that Location Service Authorization is not required.

那么我怎样才能克服这个问题呢?有没有办法配置测试目标,以便不需要位置服务授权。

回答by Joe Masilotti

Xcode 9

Xcode 9

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

Xcode 8.3.3

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


Note that it is a bit different as the method name now is addUIInterruptionMonitor and takes withDescription as an argument

请注意,它有点不同,因为方法名称现在是 addUIInterruptionMonitor 并且将 withDescription 作为参数

Xcode 7.1

Xcode 7.1

Xcode 7.1 has finally fixed a issue with system alerts. There are, however, two small gotchas.

Xcode 7.1 终于修复了系统警报的问题。然而,有两个小问题。

First, you need to set up a "UI Interuption Handler" before presenting the alert. This is our way of telling the framework how to handle an alert when it appears.

首先,您需要在显示警报之前设置一个“UI Interuption Handler”。这是我们告诉框架如何处理出现的警报的方式。

Second, after presenting the alert you must interact with the interface. Simply tapping the app works just fine, but is required.

其次,在呈现警报后,您必须与界面进行交互。只需点击应用程序就可以正常工作,但这是必需的。

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

The "Location Dialog" is just a string to help the developer identify which handler was accessed, it is not specific to the type of alert.

“位置对话框”只是一个字符串,用于帮助开发人员识别访问了哪个处理程序,它并不特定于警报类型。

Xcode 7.0

Xcode 7.0

The following will dismiss a single "system alert" in Xcode 7 Beta 6:

以下将关闭 Xcode 7 Beta 6 中的单个“系统警报”:

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

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

Beta 6 introduced a slew of fixes for UI Testing and I believe this was one of them.

Beta 6 为 UI 测试引入了大量修复程序,我相信这是其中之一。

Also note that I am calling -elementdirectly on -alerts. Calling -elementon an XCUIElementQueryforces the framework to choose the "one and only" matching element on the screen. This works great for alerts where you can only have one visible at a time. However, if you try this for a label and have two labels the framework will raise an exception.

另请注意,我是-element直接调用-alerts. 调用-elementanXCUIElementQuery强制框架在屏幕上选择“唯一的”匹配元素。这对于一次只能显示一个警报的警报非常有用。但是,如果您为一个标签尝试此操作并且有两个标签,则框架将引发异常。

回答by Joe Susnick

This was the only thing that worked for me. Using Xcode 9 fwiw.

这是唯一对我有用的东西。使用 Xcode 9 fwiw。

Also probably relevant that I was already using addUIInterruptionMonitorfor a different alert. I tried reordering them and it didn't make a difference. Could be that it's a problem in 9 when you have two, or could be I was using them wrong. In any event the code below worked. :)

也可能与我已经addUIInterruptionMonitor用于不同警报有关。我尝试重新排序它们,但没有任何区别。可能是当你有两个时 9 有问题,或者可能是我用错了它们。无论如何,下面的代码有效。:)

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

回答by null

I got it to work with this on Xcode 9.4.1, the trick was to wait for the popup to appear.

我让它在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()
    }

回答by Joao_dche

If you want to check if the alert is showing, just check for the existence of the button:

如果要检查警报是否显示,只需检查按钮是否存在:

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

it checks if the alert is showing, and if it's showing it will tap it

它检查警报是否正在显示,如果它正在显示它会点击它

回答by Hasaan Ali

On xcode 9.1, alerts are only being handled if the test device has iOS 11. Doesn't work on older iOS versions e.g 10.3 etc. Reference: https://forums.developer.apple.com/thread/86989

在 xcode 9.1 上,只有当测试设备有 iOS 11 时才会处理警报。不适用于较旧的 iOS 版本,例如 10.3 等。参考:https: //forums.developer.apple.com/thread/86989

To handle alerts use this:

要处理警报,请使用:

//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
}
// One interruption monitor is sufficient for multiple alerts

回答by Maciej

This works for all languages:

这适用于所有语言:

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

回答by Robbie Trencheny

Here's what I did to accept a notifications permission alert in any language by tapping the second button found in the (two button) dialog. The Allow button is on the right, therefore index 1.

这是我通过点击(双按钮)对话框中的第二个按钮来接受任何语言的通知权限警报的操作。允许按钮在右侧,因此索引为 1。

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

回答by Andrey

To tap allow on location alert you can call element.tap() where element is any element on your screen. So after calling tap, accessibility will tap Allow on alert and than tap on your element

要点击允许位置警报,您可以调用 element.tap(),其中 element 是屏幕上的任何元素。因此,在调用 tap 后,可访问性将点击 Allow on alert 而不是点击您的元素