web-dev-qa-db-ja.com

Xcode7 | Xcode UIテスト|位置情報サービスアラートの処理方法

Xcode7/iOS 9で導入されたXCUIApplication、XCUIElement、およびXCUIElementQueryを使用して、アプリの1つのUIテストケースを作成しています。

私は障害物にぶつかった。テストケースの画面の1つには、iOSの位置情報サービスが必要です。予想どおり、ユーザーは次のタイトルのアラートで位置情報サービスの使用を許可するように求められます:Allow “App name” to access your location while you use the app? with AllowDon'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を見つけられませんでした。例えば:

  • 画面上の位置をタップします
  • アプリの外部でアラートを取得する

どうすればこれを乗り越えることができますか?ロケーションサービスの認証が不要になるようにテストターゲットを構成する方法はありますか。

31
Taha

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はついにシステムアラートの問題を修正しました。ただし、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.0

以下は、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つある場合、フレームワークは例外を発生させます。

32
Joe Masilotti

これは私のために働いた唯一のものでした。 Xcode 9 fwiwを使用します。

また、おそらく別のアラートにaddUIInterruptionMonitorを使用していたことにも関連しています。私はそれらを並べ替えようとしましたが、違いはありませんでした。あなたが2つを持っているとき、それは9で問題であるかもしれません、または私はそれらを間違って使っていたかもしれません。いずれにしても、以下のコードは機能しました。 :)

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

アラートが表示されているかどうかを確認する場合は、ボタンの存在を確認します。

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

アラートが表示されているかどうかを確認し、表示されている場合はタップします

3
Joao_dche

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()
    }
3
null

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
2
Hasaan Ali

これはすべての言語で機能します。

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

(2ボタン)ダイアログにある2番目のボタンをタップして、任意の言語で通知許可アラートを受け入れるために私がしたことは次のとおりです。 [許可]ボタンは右側にあるため、インデックス1です。

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

ロケーションアラートで許可をタップするには、elementが画面上の任意の要素であるelement.tap()を呼び出すことができます。タップを呼び出した後、アクセシビリティはアラートで許可をタップし、要素をタップするよりも

0
Andrey