XCUITestでアプリを削除する

はじめに

アプリの起動画面に一度だけ表示される認証を実証しているアプリに対してUITestを行いたいと思いっていました。
認証の有無はUserDefaultに保存していたので、UserDefaultの値を確認したかったのですが、UITestはE2Eの為、直接NSUserDefaultsやDBを参照や変更ができないようです。

今回はUserDefaultの値を使いたいわけではなく、起動画面のテストを行いたいだけだったので、アプリを削除する方法を模索しました。

環境

Xcode Version 10.1 (10B61)

Swift version 4.2.1

コード

stack overflowに同じような質問がとうこうされていたのでそれを参考にしました。

余計なものを削ぎ落としてアプリを削除するだけにしています。

削除を行うSpringboardクラス

appDisplayNameをテストを行うアプリ名に書き換えます。
言語が英語、日本語以外の場合分岐を増やさないとテストがコケます

import XCTest

final class Springboard {
    static let appDisplayName = "テストを行うアプリ名"

    static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
    static let settings = XCUIApplication(bundleIdentifier: "com.apple.Preferences")

    static func deleteMyApp() {
        XCUIApplication().terminate()
        springboard.activate()
        XCUIDevice.shared.orientation = UIDeviceOrientation.portrait
        sleep(2)

        let icon = springboard.otherElements["Home screen icons"].scrollViews.otherElements.icons[self.appDisplayName]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.press(forDuration: 2.5)

            springboard.coordinate(withNormalizedOffset: CGVector(dx: ((iconFrame.minX + 9) / springboardFrame.maxX), dy: ((iconFrame.minY + 9) / springboardFrame.maxY))).tap()

            Thread.sleep(forTimeInterval: 1.5)

            // springboard.alerts.buttons["Delete"].firstMatch.tap()
            let languages = NSLocale.preferredLanguages
            let language = languages[0].prefix(2)
            if language == "ja" {
                springboard.buttons["削除"].firstMatch.tap()
            } else {
                springboard.buttons["Delete"].firstMatch.tap()
            }
            Thread.sleep(forTimeInterval: 0.5)
            XCUIDevice.shared.press(.home)
        }
    }

    private static func isSimulator() -> Bool {
        return TARGET_OS_SIMULATOR != 0
    }
}

呼び出し

呼び出しはsetUpメソッドの中で行いましたが別の場所でも大丈夫そうです。

 override func setUp() {
        Springboard.deleteMyApp()
        ・・・

        app.launch()
    }

ハマったこと

私の端末は日本語と英語を言語登録していたので、以下のように設定をしていまいした。
設定>一般>言語と地域>iPhoneの使用言語をEnglishにして問題ないか試したところテストがコケました。

let languages = NSLocale.preferredLanguages
let language = languages[0].prefix(2)
if language == "ja" {
                springboard.buttons["削除"].firstMatch.tap()
            } else {
                springboard.buttons["Delete"].firstMatch.tap()
            }

手動で確認してみると、iPhoneの言語設定がEnglishになっているのに関わらず削除のアラートが日本語のままでした…

Resionを変えてみたり、別の言語を入れてみたりと色々試してみたのですが、だめでふと再起動してみたところ正常に英語表記になっていました。

参考文献

iOSでUITestでアプリのデータを操作をする方法

Is there a way to reset the app between tests in Swift XCTest UI?

【Xcode9.1】iOSのUITestとかでアプリを削除したりデータをResetしたりする方法