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
Xcode7 | Xcode UI Tests | How to handle location service alert?
提问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 Allow
buttons.
我遇到了障碍。测试用例中的屏幕之一需要 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 -element
directly on -alerts
. Calling -element
on an XCUIElementQuery
forces 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
. 调用-element
anXCUIElementQuery
强制框架在屏幕上选择“唯一的”匹配元素。这对于一次只能显示一个警报的警报非常有用。但是,如果您为一个标签尝试此操作并且有两个标签,则框架将引发异常。
回答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 addUIInterruptionMonitor
for 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 而不是点击您的元素