Ionic + Typescript + Protractor でe2eテストをする


### 過去記事

+ [TypeScriptでモバイルアプリケーションを作ってみる: Ionic準備](http://qiita.com/takeo-asai/items/52bcfc76c3f3455e26bb)
+ [Typescriptでモバイルアプリケーションを作ってみる2: Class化、webpack編](http://qiita.com/takeo-asai/items/bbae027a976ee2058052)
+ [Typescriptでモバイルアプリを作ってみる その3 ユニットテスト Karma](http://qiita.com/takeo-asai/items/accd2a444449dc26e4df)

# Protractorでe2eテストする

前回はkarmaでユニットテストを行う方法を紹介しました。ですので今回はprotractorでe2eテストをする方法を紹介します。

モバイルアプリ作成用フレームワークIonicはAngularベースなので、e2eテストは[Protractor http://www.protractortest.org/#/](http://www.protractortest.org/#/)を使うのがベストです。ProtractorはそもそもAngularjs用に開発されているので非常に相性が良いためです。一応Protractorを使えば普通のユニットテストも可能ですが、e2eテストに特化しているために個々の小さなテストはkarmaを使うべきです。https://github.com/angular/protractor/blob/9144494a28dac5a0409de4c5384e933f2d2f8156/docs/faq.md


# Protractorを使ってみる

もちろんe2eテストもTypescriptで書きたいので、そのために`ts-node`を導入します。


```Bash:
$ npm install -S ts-node
```

その後、これをProtractorの設定ファイルに記述するだけでTypescriptへと変換してくれます。

```js:protractor.js
require('ts-node/register');
exports.config = {
	baseUrl: 'http://127.0.0.1:8100/',
	seleniumAddress: 'http://127.0.0.1:4723/wd/hub',
	specs: [
		'./src/**/*.e2e.ts'
	],
	exclude: [],
	framework: 'mocha',
	allScriptsTimeout: 110000,
	directConnect: true,
	capabilities: {
		'browserName': 'chrome',
		'deviceName' : 'Android Emulator',
		'chromeOptions': {
			args: ['--disable-web-security'],
		}
	},
	mochaOpts: {
		timeout: 30000 // very important
	}
}
```

mochaOptsでtimeoutを指定しないとデフォルトの2,000msとなってしまい、少し時間のかかる操作をしたりするとタイムアウトでエラーとなってしまうので、それなりに長い時間を指定する必要があります。


この設定が終わったら適当にテストを記述します。例として何もしない、必ず成功するテストをおいておきます。

```ts:src/app.e2e.ts
describe("This is", () => {
	it("always true", () => {
	});
})
```

## iOS Simulatorでe2eテストする

ProtractorのデフォルトではChromeでe2eテストを行いますが、Chrome以外でももちろん可能です。今回Ionicでモバイルアプリを作成しているので、iOS Simulatorでe2eテストを行ってみます。

とりあえず参考程度に、

+ http://kitak.hatenablog.jp/entry/2015/05/10/144628
+ http://qiita.com/tanakaworld/items/316c46bfde8497fca961
+ https://github.com/angular/protractor/blob/master/docs/mobile-setup.md

少し情報が古いのでコマンドが一部変わっていたりしますが基本の流れは一緒です。


それではまずはインストールを行います。

```Bash:
$ npm i -g appium appium-doctor authorize-ios
$ sudo authorize-ios
```

新しいversionではappiumだけインストールしても、doctorやauthorizeはインストールされないため別途入れる必要があります。また、過去versionではauthorize_iosとアンダーバーでしたが、いつの間にかハイフンへと変更されています。

authorize-iosのsudoは、/Applications 以下にあるSimulatorの実行権を変更するために必要です。

authorizeが終わりましたら`appium-doctor`で実行可能か診断します。

```Bash:
$ appium-doctor --ios
info AppiumDoctor ### Diagnostic starting ###
info AppiumDoctor  ✔ Xcode is installed at: /Applications/Xcode.app/Contents/Developer
info AppiumDoctor  ✔ Xcode Command Line Tools are installed.
info AppiumDoctor  ✔ DevToolsSecurity is enabled.
info AppiumDoctor  ✔ The Authorization DB is set up properly.
info AppiumDoctor  ✔ The Node.js binary was found at: /Users/YOURNAME/.nodebrew/current/bin/node
info AppiumDoctor  ✔ HOME is set to: /Users/takeo
info AppiumDoctor ### Diagnostic completed, no fix needed. ###
info AppiumDoctor 
info AppiumDoctor Everything looks good, bye!
info AppiumDoctor 
```

`Everything looks good, bye!`ならば問題ありませんので、続いてProtractorの設定ファイルを変更します。


```Json:protractor.js
  directConnect: false,
  capabilities: {
    'browserName': 'safari',
    'appium-version': '1.5.3',
    'platformName': 'iOS',
    'platformVersion': '9.3',
    'deviceName': 'iPad Pro'
  },
```

directConnectとcapabilitiesの変更を行います。appium-versionは`$ appium -v`で取得できますのでそれを用いてください。特に重要なのがdirectConnectの設定部分で、ChromeとFirefoxしかdirectConnectが使えないので必ず`false`に変更する必要が有ります。`directConnect: false` trueだとダメです。


これでProtractorでiOS Simulatorを使う設定は完了です。ですが、当たり前ですがSimulatorを毎回起動しなおしてテストするのは起動にかかる時間を考えると非効率ですし、かと言って起動しっぱなしだとメモリを食うので貧弱な開発環境だと厳しい物が有ります。iOS Simulatorの使えるCIを活用するのが現実的な解決策でしょうか？何か良い解決策をお持ちの方は教えていただけると幸いです。


# Protractor on CircleCI

ここからはProtractorをCircleCIで動かす場合のTipsです。特にIonicを使っている場合にハマるであろうポイントについて記述しておきます。

Protractorを使ってテストをするには予めサーバーを立てておく必要があるのですが、そのサーバーを立てるコマンドに __`$ ionic serve`を使っていると、CircleCIはありがたいことに其のサーバーの起動後すぐにシャットダウンしてくださるのでe2eテストが不可能です__。Ionicを使ってCircleCIでe2eテストをする際にハマる最大のポイントかと思われます。ですので、`$ ionic serve`以外のhttp serverを用意する必要があります。この場合、cordova.jsというファイルが生成されないのでエラーが起きてしまいますが、実機チェックの時以外は常に空のファイルですので気にする必要はありません。


```:circle.yml
npm install -g http-server
cd www && http-server -p 8100:
	background: true
```

webpackのdevServerがありますが、高機能すぎるのでここでは適当ではないかと思われます。