Xcode7/iOS 9で導入されたXCUIApplication、XCUIElement、およびXCUIElementQueryを使用して、アプリの1つのUIテストケースを作成しています。
私は障害物にぶつかった。テストケースの画面の1つには、iOSの位置情報サービスが必要です。予想どおり、ユーザーは次のタイトルのアラートで位置情報サービスの使用を許可するように求められます:Allow “App name” to access your location while you use the app?
with Allow
&Don't Allow
ボタン。
問題は、OS自体によってアラートが表示されるため、アプリケーションの要素サブツリーには存在しないようです。
私は次を記録しました:
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
UI記録でも同様のコードが生成されました:
XCUIApplication().alerts["Allow “App Name” to access your location while you use the app?"].collectionViews.buttons["Allow"].tap()
この問題を乗り越えるAPIを見つけられませんでした。例えば:
どうすればこれを乗り越えることができますか?ロケーションサービスの認証が不要になるようにテストターゲットを構成する方法はありますか。
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons["Allow"]
if allowBtn.exists {
allowBtn.tap()
}
_ = 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はついにシステムアラートの問題を修正しました。ただし、2つの小さな落とし穴があります。
最初に、アラートを表示する前に「UI Interuption Handler」をセットアップする必要があります。これは、表示されたときにアラートを処理する方法をフレームワークに伝える方法です。
第二に、アラートを提示した後、インターフェイスを操作する必要があります。アプリをタップするだけで問題なく動作しますが、必須です。
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 Beta 6の単一の「システムアラート」を却下します。
let app = XCUIApplication()
app.launch()
// trigger location permission dialog
app.alerts.element.collectionViews.buttons["Allow"].tap()
ベータ6では、UIテストに多数の修正が導入されましたが、これはそのうちの1つだと思います。
また、-element
で-alerts
を直接呼び出していることに注意してください。 XCUIElementQuery
で-element
を呼び出すと、フレームワークは画面上の「唯一無二の」一致する要素を選択します。これは、一度に1つしか表示できないアラートに最適です。ただし、ラベルに対してこれを試行し、ラベルが2つある場合、フレームワークは例外を発生させます。
これは私のために働いた唯一のものでした。 Xcode 9 fwiwを使用します。
また、おそらく別のアラートにaddUIInterruptionMonitor
を使用していたことにも関連しています。私はそれらを並べ替えようとしましたが、違いはありませんでした。あなたが2つを持っているとき、それは9で問題であるかもしれません、または私はそれらを間違って使っていたかもしれません。いずれにしても、以下のコードは機能しました。 :)
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons["Allow"]
if allowBtn.exists {
allowBtn.tap()
}
アラートが表示されているかどうかを確認する場合は、ボタンの存在を確認します。
if (app.alerts.element.collectionViews.buttons["Dismiss"].exists)
{
app.alerts.element.collectionViews.buttons["Dismiss"].tap()
}
アラートが表示されているかどうかを確認し、表示されている場合はタップします
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()
}
xcode 9.1では、テストデバイスにiOS 11がある場合にのみアラートが処理されます。 10.3などの古いiOSバージョンでは動作しません。参照: 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
これはすべての言語で機能します。
let springboard = XCUIApplication(bundleIdentifier: "com.Apple.springboard")
let allowBtn = springboard.buttons.element(boundBy: 1)
if allowBtn.exists {
allowBtn.tap()
}
(2ボタン)ダイアログにある2番目のボタンをタップして、任意の言語で通知許可アラートを受け入れるために私がしたことは次のとおりです。 [許可]ボタンは右側にあるため、インデックス1です。
let handler = addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in
alert.buttons.element(boundBy: 1).tap()
return true
}
app.tap()
ロケーションアラートで許可をタップするには、elementが画面上の任意の要素であるelement.tap()を呼び出すことができます。タップを呼び出した後、アクセシビリティはアラートで許可をタップし、要素をタップするよりも