AngularJS + Cordova なアプリに Protractor + Appium を使って iOS 実機で E2E テストを実施する方法
以前、AngularJS + Cordova なアプリに Protractor + Appium を使って iOS シミュレータで E2E テストを行う方法を紹介した。
今回はその続きで、今度は iOS 実機で E2E テストを行う方法を紹介する。
前回紹介した環境設定をしてあるのが前提になる。
実際のコードはコチラ
今回紹介したパッケージとサンプルコードを利用し、AngularJS + Cordova なアプリで Appium を使った E2E テストを行うサンプルプロジェクトを作成した。以下を参考にしてほしい。
今回の例では、Appium と Protractor の起動は、Gulp タスクとして定義している。gulpfile.js はコチラ。
WebDriver Agent の設定
プロジェクトにローカルインストールした Appium の配下にある appium-xcuitest-deriver が WebDriverAgent を抱えているので、コレの設定をする。
$ cd ./node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/
$ sh ./Scripts/bootstrap.sh -d
-e Fetching dependencies
# XCode プロジェクトを開く
$ open ./WebDriverAgent.xcodeproj
XCode 上で以下のように設定を変更した。
- Identity
    - Bundle Identifier
        - com.facebook.WebDriverAgentLib → 個人で適当なアプリ識別子に変更する
 
 
- Bundle Identifier
        
- Signing
    - Team
        - None → 自分のチームを指定する
 
 
- Team
        
- Status
    - エラーが出ている場合は少し上にある「Automatically manage signing」にチェックを付ける
 
このまま XCodeBuild をしても以下のようなメッセージが出る。
Testing failed:
Signing for "WebDriverAgentRunner" requires a development team. Select a development team in the project editor.
Code signing is required for product type 'UI Testing Bundle' in SDK 'iOS 10.3'
引き続き WebDriverAgent.xcodeproj を XCode で開き、左ペインの「TARGETS」から「WebDriverAgentRunner」を選択する。
- General タブ
    - Signing
        - Team : None → 自分のチームを指定する
 
- Status
        - The app ID "com.facebook.WebDriverAgentRunner" cannot be registered to your development team.と出ているはず。
 
 
- Signing
        
- Build Settings タブ
    - Product Bundle Identifier (右上の検索窓から検索すると楽)
        - com.facebook.WebDriverAgentRunner → 個人で適当なアプリ識別子に変更する
 
 
- Product Bundle Identifier (右上の検索窓から検索すると楽)
        
これで Status のエラーが消える。
iOS 実機を繋いでおき、以下のコマンドでビルドする。
$ xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=【UDID】' test
これで実機上に WebDriver がインストールされた。コンソールは「XCTRunner[893:177871] ServerURLHere->http://192.168.2.3:8100<-ServerURLHere」という表示になったらそのまま監視状態になるので Ctrl + C で終了させる。
UDID の調べ方
- iOS 実機を Mac に USB 接続する。
- iTunes を開き、「概要」画面にある「シリアル番号」部分をクリックすると「UDID」に表示が切り替わるので、右クリック → コピー でコピーする。
- もしくは先程インストールした「libimobiledevice」から以下のコマンドを叩くと UDID が取得できる。
$ idevice_id --list
E2E テストを開始する
以下の手順でテストを開始する。事前に iOS 実機を USB に繋いでおくこと。
- iOS 実機にアプリをインストールする
- iOS 実機に WebDriver をインストールする
- Appium サーバを起動する
- ios-webkit-debug-proxy を起動する
- Protractor を実行する
1. iOS 実機にアプリをインストールする
事前に iOS 実機にアプリをインストールしておく。既にインストールできている場合は飛ばして良い。
# iOS 実機向けにビルド・インストールする
$ cordova run ios
2. iOS 実機に WebDriver をインストールする
これも既にインストールできている場合は飛ばして良い。「XCTRunner[893:177871] ServerURLHere->http://192.168.2.3:8100<-ServerURLHere」のコンソール出力で止まるので Ctrl + C で抜ける。
$ xcodebuild -project ./node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=【UDID】' test
3. Appium サーバを起動する
Appium サーバを起動しておく。
# Gulp タスクからローカルインストールした Appium を起動する
$ npm run gulp appium
Appium をグローバルインストールしておき、$ appium で起動した場合は途中で WebDriver Agent のビルドが失敗して上手くいかなかった。Appium 自身の配下にある WebDriver Agent を使用しようとして、未設定のためにビルドが失敗するものと思われる。
コンフィグ設定は以下のように記述して動作したが、デフォルト設定とほとんど同じため、コンフィグ設定を指定せずとも動作するものと思われる。
/* nodeConfig.json */
{
  "configuration": {
    "cleanUpCycle": 2000,
    "timeout": 30000,
    "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
    "url": "http://127.0.0.1:4723/wd/hub",
    "host": "127.0.0.1",
    "port": 4723,
    "maxSession": 1
  }
}
4. ios-webkit-debug-proxy を起動する
Appium サーバより後に起動する。コンソールには何やらバイナリが出力される。
$ ios_webkit_debug_proxy -c 【UDID】:27753 -d
5. Protractor を実行する
iOS 実機のロックは解除しておくこと。
$ npm run gulp e2e
protractor.conf.js の設定内容を検証した結果は以下のとおり。
消したらダメだった設定項目
- seleniumAddress: 'http://127.0.0.1:4723/wd/hub'- Appium サーバを認識するために必要。
 
- browserName: ''- 必須。'Safari'などにすると Safari ブラウザが開いてしまうので、空値''にしておくのが慣例。
 
- 必須。
- app: './platforms/ios/build/device/【アプリ名】.app'
- bundleId: 【アプリ識別子】- appと- bundleIdはセットで必須かつ正しく設定すること。- appに記載のパスで辿れる- .appと同じものが実機にインストールされていて、識別子が- bundleIdと一致しないと正しく動作しない。
- 一度誤った設定で Protractor から Appium を通ると、Appium の動作がおかしくなり、再テストができなくなる。その場合は一度 Appium サーバを完全にシャットダウンし、WebDriver の再インストールからやり直すと綺麗に戻る ($ ps -A | grep appiumでプロセス ID を取得し$ kill 【プロセス ID】で確実に終了できる)。
- ビルドのされ方によっては、appに記載のパスではなく'./platforms/ios/build/emulator/ディレクトリにビルドされてしまうことがある。その場合は実機を USB 接続した状態で$ cordova run iosより改めて実機向けにビルドするとdevice/ディレクトリにビルドされる。
 
- deviceName: 【iOS 実機名?】- 必須だが、実際の端末名と一致していなくても動作した。
- シミュレータを使用している場合はココで 'iPhone 7'などとプラットフォーム名を指定していた。
 
- udid: '【UDID】'
- platformName: 'iOS'
- platformVersion: '10.3'- udid・- platformName・- platformVersionはセットで必要かつ正しく設定すること。バージョンは- 10.3.1などメンテナンスバージョンを指定しても良い (書いていても無視されるので存在しない誤ったメンテナンスバージョンを記載しても問題なし)。
- udidは使用する検証機の UDID にする。WebDriver のビルド時に設定した UDID と一致していないといけない。
 
- autoWebview: true- trueにしないとアプリが起動したところで E2E テストがエラーになった。アプリの環境によるのかもしれない。
 
消して良い設定項目
- baseUrl: ''- テスト中に browser.baseUrlで取得できるものになるベース URL の設定だが、iOS 向けにonPrepare()内でbrowser.baseUrlを書き換えているため不要。
 
- テスト中に 
書かなくても影響ないが、入れておくと良いと思われる設定項目
- fullReset: false- trueにすると、シミュレータの場合に、アプリディレクトリを削除してアプリを初期化するというもの。実機でのテスト時は本設定は影響しない様子。
- 参考 : http://www.rightqa.com/appium-desired-capabilities/
 
- autoWebviewTimeout: 20000- WebView のタイムアウト。
 
- autoAcceptAlerts: true- 自己証明書を受け入れるアラートが出る時に自動で受け入れる。
- 参考 : Appiumでsslの自己証明書の許可をする - φ(・・*)ゞウーン カーネルとか弄ったりのメモ
 
というわけで、以下の設定が最小限の設定内容となった。
exports.config = {
  // Appium サーバの URL を指定する
  seleniumAddress: 'http://127.0.0.1:4723/wd/hub',
  
  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    // 必須設定
    browserName: '',
    autoWebview: true,
    
    // テスト対象のアプリ情報
    app : './platforms/ios/build/device/【アプリ名】.app',
    bundleId: '【アプリ識別子】',
    
    // テストを実施する iOS 実機情報
    deviceName : '【iOS 実機名】',
    udid : '【UDID】',
    platformName : 'iOS',
    platformVersion: '10.3',
    
    // その他設定
    // iOS シミュレータの場合にアプリのディレクトリを削除してアプリを初期化する場合は true
    fullReset : false,
    // WebView のタイムアウト
    autoWebviewTimeout: 20000,
    // 自己証明書の確認アラートが表示されるとき自動で許可する場合は true
    autoAcceptAlerts : true
  },
// 以下略
というワケで手順まとめ
- iOS 実機を USB 接続する。
- iOS 実機にテスト対象アプリが入っていなければインストールする。
    - $ npm run run:ios
- ./platforms/ios/build/device/【アプリ名】.appが生成されていることを確認しておくと良い。
 
- WebDriverAgent とその配下にある WebDriverAgentRunner の識別子 (Bundle Identifier) を端末ごとにユニークなモノに変更する。
    - $ open ./node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj
- 左ペイン TARGETS : WebDriverAgentLib → General タブ → Bundle Identifier
- 左ペイン TARGETS : WebDriverAgentRunner → Build Settings タブ → Product Bundle Identifier
- Appium が起動する際に再ビルドするようなので、以下の手順 4. を飛ばす場合もやっておいた方が良い。
 
- iOS 実機に WebDriver が入っていなければインストールする。
    - $ xcodebuild -project ./node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=【UDID】' test
- ServerURLHereとコンソールに出力されたら- Ctrl + Cで終了する。
 
- 1つ目のターミナルで Appium サーバを起動する。
    - $ npm run gulp appium
 
- 2つ目のターミナルで ios-webkit-debug-proxy を起動する。
    - $ ios_webkit_debug_proxy -c 【UDID】 -d
 
- protractor.conf.jsに実機の UDID を記載する。- app・- bundleIdもついでに確認しておく (iOS シミュレータの場合と設定が異なる部分なので)。
 
- 3つ目のターミナルで Protractor を実行する。
    - $ npm run gulp e2e
 
テスト中について
テスト中は Safari インスペクタでの参照は不可。
テストを終了する
テストを終了する際は以下の順に終了処理を行う。
- npm run gulp e2eでのテストが完了するまで待つか、- Ctrl + Cで終了させる。
- ios-webkit-debug-proxyを起動しているターミナルを- Ctrl + Cで終了させる。
- npm run gulp appiumを起動しているターミナルを- Ctrl + Cで終了させる。
以上。