Protractor × CoffeeScript × AngularJS （導入編）

割りと早めに気が向いたので導入方法書きます。
[Protractor の使い方はこちら](http://qiita.com/amoO_O/items/19b8e44af4531455d85a)

# node_modules
```bash
npm install --save-dev coffee-script
npm install --save-dev protractor
npm install --save-dev grunt-protractor-runner
npm install --save-dev protractor-coffee-preprocessor
npm install --save-dev grunt-exec
```

- coffee-script
    - CoffeeScript のコンパイラ
    - はじめ -g で入れていたのだがプロジェクトの中に入れないと使えなかった
- protractor
    - angularJS 御用達の E2E テストフレームワーク
    - selenium を angularJS プロジェクトで使えるようによしなにカスタマイズしている
- grunt-protractor-runner
    - protractor を grunt のタスクとして実行するためのモジュール
- protractor-coffee-preprocessor
    - CoffeeScript で書いたテストを実行するための、 protractor のプラグイン
- grunt-exec
    - grunt タスクとして shell コマンドを実行するためのモジュール
    - 他にも grunt-shell-spawn などがある。shell コマンドを実行できれば何でも良い

# 設定
## protractor.conf.js
```js:./protractor.conf.js
"use strict";

exports.config = {
  seleniumServerJar: "node_modules/protractor/selenium/selenium-server-standalone-2.42.2.jar",
  capabilities: {
    browserName: "chrome"
  },
  specs: [
    "test/e2e/**/*.coffee"
  ],
  baseUrl: "http://localhost:9000",
  framework: "jasmine",
  plugins: [
    "protractor-coffee-preprocessor"
  ],
  onPrepare: function() {
    // Disable animations so e2e tests run more quickly
    var disableNgAnimate = function() {
      angular.module("disableNgAnimate", []).run(["$animate", function($animate) {
        $animate.enabled(false);
      }]);
    };

    browser.addMockModule("disableNgAnimate", disableNgAnimate);

    // Store the name of the browser that's currently being used.
    browser.getCapabilities().then(function(caps) {
      browser.params.browser = caps.get("browserName");
    });
  },
  jasmineNodeOpts: {
    showColors: true,
    isVerbose: false,
    defaultTimeoutInterval: 30000
  }
};
```

- seleniumServerJar
    - selenium の本体
    - 既に立ち上がっている selenium を使用する、seleniumAddress もあるが、起動＆終了を自動で行う方法がいまいちわからなかったのでこちらを使用している。 selenium のバージョン番号を直接書いているのが少し気持ち悪い。
- capabilities
    - テストに関する情報？設定？ 未調査。
    - 他に pratform とか version などを指定できる（らしい）
- specs
    - テストファイルの在処
- baseUrl
    - テストするサイトの baseUrl
    - テストファイル内で、 `browser.baseUrl` という形で取得できる
- framework
    - テスト フレームワークを指定
    - mocha なども選べるっぽい
- plugins
    - 今回の肝。CoffeeScript で書かれた テストファイルを実行するためのプラグインを指定
- onPrepare
    - テスト実行前に呼び出される関数
    - ここでは、スピードアップのために アニメーションをオフにしている
    - 総本山 angularJS のパクリ： https://github.com/angular/angular.js/blob/36831eccd1da37c089f2141a2c073a6db69f3e1d/protractor-shared-conf.js#L10
- jasmineNodeOpts
    - showColors: true
        - 人生に彩りを
    - isVerbose: false
        - 振り返るな
    - defaultTimeoutInterval: 30000
        - 30 秒ルール


## Gruntfile.coffee
```coffeescript:./Gruntfile.coffee
module.exports = (grunt) ->
  grunt.initConfig
    # ...
    protractor: 
      options:
        keepAlive: true # 失敗しても立ち止まるな
        noColor: false # 人生に彩りを
      coffee:
        configFile: "protractor.conf.js" # 細かいことは他人任せ
    exec:
      webdriverUpdate: "node_modules/protractor/bin/webdriver-manager update"
  grunt.registerTask "test:protractor", [
    "exec:webdriverUpdate"
    "clean:server"
    "concurrent:server"
    "autoprefixer"
    "configureRewriteRules"
    "connect:livereload"
    "protractor:coffee"
  ]
```

- exec:webdriverUpdate
    - webdriver の update を行う
    - webdriver を start する前にこれが必要。忘れないように自動化
- clean:server
    - これと続く3つ(configureRewriteRules まで）は、サーバーのセットアップのためのタスク
    - 環境によってだいぶ違ってくるので、鵜呑みにはしないでください。
    - このタスク自体は、サーバーに置くべきファイル群をクリーンアップしている
- concurrent:server
    - サーバーに必要なファイルをおく作業。
        - coffee ファイル群を js ファイルにコンパイル
        - haml ファイル群を html ファイルにコンパイル
        - sass ファイル群を css ファイルにコンパイル
        - bower_components のファイル群をサーバーにコピー
        - フォントや画像などその他のファイルをサーバーにコピー
- autoprefixer
    - ベンダープレフィックスを自動でつける
- configureRewriteRules
    - apache の mod_rewrite の代わりみたいなもの
    - rewrite ルールを適用する
- connect:livereload
    - サーバー起動
    - localhost:9000 を立ち上げている
- protractor:coffee
    - protractor によるテストの本体
    - このタスクによって selenium 用の サーバーが立ち上がり、localhost:9000 に対して DOM 操作などを行う

# テストの実装
```coffeescript:test/e2e/sampleTest.coffee
"use strict"

describe "top page は", ->
  url = (path) -> "#{browser.baseUrl}#{path}"
  beforeEach ->
    browser.get url "/top"
    browser.waitForAngular()

  it "LOGIN ボタンを押すと ログイン ページへ遷移する", ->
    button = By.id("LOGIN")
    button.click()
    expect(browser.getLocationAbsUrl()).toEqual url "/login"
```

# 実施
コンソール上で以下を実行することで、E2E テストを実行することができる

```bash
grunt test:protractor
```