Vue.js の 単体テストについて、webpackなどビルドツールがない状況での環境を構築する

# 背景
[公式の単体テスト](https://jp.vuejs.org/v2/guide/unit-testing.html)でも、ビルドツールありきのテスト環境となっている。
ただ、自分の環境では、webpackなどビルドツールは使用しておらず、Vue.js の単体を使用している。
そんな状況だが単体テストは行いたい。

# 問題
公式でもwebpackなどを使用しているためか、vueのテストの情報は、ビルドツールありきになっている。
ただ、単体テストのためだけにwebpackを入れるか？ となるとそれはそれで、めんどくさい。
ちょろっと作ったvueアプリケーションの整合性が担保できればそれでいいので、できる限り手間をかけずにテストを行いたい。

# 達成目標

1. webpackは使わない.
2. jasmine + karma での vue.js の単体テスト
3. ヘッドレスなテスト (phantomjs使うよ)
4. coverageは取れるようにしておく

と以上の４点が達成できればOKということにします。

## テストを行うvueアプリケーションについて

テスト実施環境のサンプルとして、Hello world レベルのvueアプリケーションを作成した
[テストを行うvueアプリ](https://yohei-takara.github.io/jasmine-unit-test/vue/)
こいつについて、今回は、このアプリケーションの単体テストを実施して行きます。

## 注意事項

webpackなどビルドツールは使用しませんが、ライブラリやフレームワークの管理として、npmを使用します。
node.js と npm の versionは下記のようになります。

```
$ node -v
v7.3.0
$ npm -v
3.10.10
```


# 必要なライブラリなど依存関係

ライブラリやフレームワークをpackage.jsonに追加します。

```package.json
  "devDependencies": {
    "jasmine": "^2.5.3",
    "karma": "^1.6.0",
    "karma-coverage": "^1.1.1",
    "karma-jasmine": "^1.1.0",
    "karma-phantomjs-launcher": "^1.0.4",
    "karma-spec-reporter": "0.0.31",
    "phantomjs-prebuilt": "^2.1.14"
  },
  "dependencies": {
    "vue": "^2.2.6"
  }
```

# karmaの設定

プロダクトコードは、`src/script/`以下に配置し、
テストコードは、`test/unit/spec/`に配置します。

```karma.conf.js
module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      "node_modules/vue/dist/vue.js",
      "src/script/*.js",
      "test/unit/spec/*.js"
    ],
    exclude: [],
    preprocessors: {
      'src/script/*.js': ['coverage']
    },
    reporters: ['spec', 'coverage'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['PhantomJS'],
    singleRun: false,
    concurrency: Infinity
  })
}
```

# プロダクトコード

プロダクトコードとして、簡単なvueのサンプルを作成します。

```product.js
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello ',
    name: ""
  },
  methods: {
    greet: function (event) {
      this.name = "Vue!";
    },
    clrearGreet: function (event) {
      this.name = "";
    }
  }
})
```

# テストコード

jasmineの解説が目的ではないので、テストコードの細かい解説は省略させていただきます。
テストを通していない箇所が正しく出るかも確認したいので、`clrearGreet`について、敢えてテストは書いていません。


```spec.js
describe('vue アプリのテスト', function() {
  it('has a created hook', function() {
    expect(typeof app.$data).toBe('object');
  });
  it('vueコンポーネントのdata検証', function() {
    expect(app.$data.message).toBe('Hello ');
    expect(app.$data.name).toBe("");
  });
  it('vueコンポーネントのmethods検証', function() {
    expect(app.$data.name).toBe("");
    app.greet()
    expect(app.$data.name).toBe('Vue!');
  });
});
```

# 実行結果


## テスト結果

```
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR LOG: '[Vue warn]: Cannot find element: #app '

  vue アプリのテスト
    ✓ has a created hook
    ✓ vueコンポーネントのdata検証
    ✓ vueコンポーネントのmethods検証

PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 3 of 3 SUCCESS (0.001 secs / 0.004 secs)
TOTAL: 3 SUCCESS
```

## カバレッジ

うまく結果が出ています。
テストを通していない箇所についてもちゃんとでていますね。

![カバレッジ.png](https://qiita-image-store.s3.amazonaws.com/0/50028/dd2075bb-b910-82ea-3f5c-cbb67ef8872f.png)

![カバレッジ1.png](https://qiita-image-store.s3.amazonaws.com/0/50028/72731494-b4b2-9665-90d4-882688fc1271.png)


# おわりに

これで、プロダクトコードとテストコードを追加していっても特に設定を変えずにテストを行うことができる環境が整いました。
ただ、これでもテスト環境の導入としては、ちょっとめんどくさいかと思うので、もっと楽にヘッドレステストできないものかと思いますので、この辺は今後ももう少し模索していこうかと思います。
なにかいい方法があれば教えていただけると幸いです。

[本記事で使用してるソースコードは、Githubに公開してます。](https://github.com/yohei-takara/jasmine-unit-test/tree/master/vue)