この記事は、Vue.js Advent Calender 2015 7日目の記事です。
Vueify で書かれた Vue.js のコンポーネントを単体テストしましょう。
本記事では
- Vueify でコンポーネントを書き
- Babel でトランスパイルし
- Browserify で1ファイルに結合して運用しているコンポーネントを
- Jasmine で単体テストを書き
- Karma で動かす
までを解説していきます。
前半の Vueify + Babel + Browserify までは、
はじめてのVue.js - 単一ファイルコンポーネントを作れる環境構築編 (npm + gulp + browserify + babel + vueify)に準じた環境を前提としますのでご了承ください。
また、一部で はじめてのVue.js - タスクリストの実装から学ぶコンポーネントベースアプリ で作成したコードをベースにテストを作成します。
環境構築
まず、Karma を導入しましょう。Karma は様々なブラウザで様々なテストスイートを走らせ、レポートを作成する「テストランナー」に当たるツールです。インストールは下記コマンドから行います。
$ npm install --save-dev karma
さて、 Karma はインストールしただけでは意味があまりありません。あくまでもテストランナーであるので、実際にテストを記述する「テストフレームワーク」とテスト実行環境用のブラウザプラグインをそれぞれインストールする必要があるためです。
今回はテストフレームワークとして Jasmine を使い、ブラウザには Google Chrome を使うこととします。そこで、 karma-jasmine と karma-chrome-lancher もインストールします。インストールは次のコマンドで行います。
$ npm install karma-jasmine karma-chrome-launcher --save-dev
最後に Karma の設定フィアルを用意します。 Karma には設定ファイルを生成するウィザードが付属しているので、ウィザード経由で初期設定するのが良いでしょう。
次のコマンドでウィザードを起動してください。
$ ./node_modules/karma/bin/karma init
ウィザードの中で質問される項目について超訳と記入例を付属しておきます。
Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine # 使用するテストフレームワーク。ここでは jasmine
Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no # Require.js を使用するか? Browserify 使ってるので no
Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome # テストで使用するブラウザ。PhantomJS とか便利だけど、今回は Chrome
> # 使用するブラウザの選択終わったら空行で Enter 入力して選択を終わらせる
What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> spec/**/*_spec.js # テストファイルの場所。好みでいいけど、著者はこうしてる。
> # 選択が終わったら空行で Enter 入力して選択を終わらせる。
Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
> # 無視するファイルを選ぶ。入力が終わったら空行で Enter を入力して選択を終わらせる。
Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> no # Karma に watch させたいか? gulp でやるなら no で大丈夫のはず
Config file generated at "/Users/ayasuda/src/hello_vuejs/karma.conf.js".
# ↑
# ここに設定ファイルができますよ!
設定ファイルが生成されたら、早速テストを書いてみましょう。次のような、絶対にパスするテストを spec/my_first_spec.js に書いてみてください。
describe('my first spec', function () {
it ('is ok', function() {
expect(true).toBe(true);
})
})
テストが書けたらここまでの動きを試してみましょう。ブラウザが立ち上がってテストが実行されるはずです!テストの実行は次のコマンドで行います。
$ ./node_modules/karma/bin/karma start karma.conf.js --single-run
(Appendix) gulp と npm に包む
毎度、上のコマンドを打つのはかなり手間です。また、ビルドシステムに包むことで、テスト前後に様々な処理をかませられるようにしておいた方が後々便利でしょう。
いつも通り karma の実行を gulp タスクに包み、かつ npm run test
で実行できるようにしておきましょう。
まずは、 gulp の karma プラグインをインストールします。
$ npm install --save-dev gulp-karma
プラグインがインストールできたら、gulp に test タスクを追加しましょう。
var karma = require('karma').Server
gulp.task('test', function() {
runner = new karma({
configFile: __dirname + '/karma.conf.js',
singleRun: true
})
runner.start()
})
gulp のタスクを追加したら、 npm でさらにラップします。
{
"scripts": {
"build": "gulp build",
"test": "gulp test"
},
}
ここまでで npm run test
と打つことで karma のテストが動くようにできました。
早速試してみてください。
Babel と Browserify をテスト内でも適用する
単一ファイルコンポーネントを ES6 で書くために Babel を使っている場合や、ひとつのファイルにまとめるために Browserify を使用している場合、このままでは karma でテストが書けません。
Browserify は単一の、たとえば bundle.js とかにファイルをまとめてくれますが、単体テスト前に動くわけではないからです。
まずは 動かないことを試してみましょう 次のファイルを用意してください。
はじめてのVue.js - タスクリストの実装から学ぶコンポーネントベースアプリ で作成した Task
クラスをただ初期化するだけのコードですが、 model/task.js は ES6 で書かれています。ファイルが書けたら npm run test
してみましょう。
describe('Task', function() {
var Task = require('../model/task').default
it('is ok', function() {
var task = new Task({title: "test"})
expect(task.title).toBe("test")
})
})
・・・もちろん動かなかったはずです。これを動くようにするために、 karma に browserify プラグインをインストールします。インストールは下記コマンドから行います。
$ npm install --save-dev karma-browserify
プラグインのインストールができたら karma の設定ファイルにプラグインを使用するための各種設定値を記していきます。
module.exports = function(config) {
config.set({
frameworks: ['browserify', 'jasmine'], // browserify プラグインを追加する
preprocessors: {
// **_spec.js を読み込む際に browserify してからファイルを読みこむ
'test/**/*_spec.js': ['browserify'],
},
// browserify の設定
// ファイル中の require を解決するのがメインの仕事
browserify: {
debug: true,
// require の解決だけじゃなくて、 vueify して babelify もする
transform: ['vueify', ['babelify', {"presets": "es2015"}] ]
},
})
}
設定を書いたら、再度 npm run test
してみてください。今度はうまくテストが動いたはずです!!
注意
package.json に browserify の設定を書いている場合、
karma.conf.js に browserify の設定を書いてはいけません!
2重に読み込まれ、結果として vueify した結果に vuiefy が適用されることで
require した時に空オブジェクト が返ることになります!
(ここのハマって4時間かかった)
Vueify で書かれた単一ファイルコンポーネントをテストする
ここまでできればあとは簡単です。公式ガイドに書かれているように 例えば下記のような組み合わせのテストを書くことができます!
describe('my-task', function () {
// ソースモジュールを require
var myTask = require('../../components/task.vue')
it('created hook が定義されている', function () {
expect(typeof myTask.created).toBe('function')
})
})
<style>
.my-task {
color: #f0c;
}
</style>
<template>
<div class="my-task">
<label>タイトル</label>
<input type="text"
v-model="task.title"
placeholder="タイトルを入力してください"
v-on:keyup.enter="saveTask"
v-on:blur="saveTask"
>
<span v-on:click="removeTask">削除</span>
</div>
</template>
<script>
var Task = require('../model/task').default
export default {
props: {
task: { type: Object, default: () => { return new Task } }
},
methods: {
saveTask: function() {
this.$dispatch('task-changed')
},
removeTask: function() {
this.$dispatch('task-removed', this.task)
},
},
created: function() {
console.log("created")
}
}
</script>