karma+mocha+power-assertでDOM操作を含むユニットテストをES6で書く
テスト周りは以前にmocha
+chai
、QUnit
を少し触った程度であまり詳しくなく、少しずつ慣れていかなきゃなぁと感じていました。
そこで今回は簡単なモジュールを、コード本体とテストコードの両方をES6
で書いてみました。
タイトルにもありますが、主要なライブラリは以下を使っていきます。
- karma
0.13.14
: テストランナー - mocha
2.3.3
: テスティングフレームワーク - power-assert
1.1.0
: アサーション
ちなみに、この記事はscrollable-elements.jsという、ES6
用のモジュールを作った時の内容となります。
指定したセレクタの中からスクロール可能な要素を取得するという、なんともニッチな内容のモジュールです。笑
興味のある方は以下リポジトリよりご確認いただけたらと思います。
方針など
モジュール、テストを書くにあたって以下の方針に沿っていきたいと思います。
CLI
からテストの実施可能DOM
(UI
)のユニットテストができる- モジュールを
ES6
で実装 - テストコードも
ES6
で babel
で変換するけど、src
からdist
へ、みたいな一時ファイルを生成したくない (直接実行したい)
今回テーマとするモジュール
以下の様にして、指定した要素の属性値を設定する簡単なモジュールをテストする前提で進めていきます。
import setAttributes from "./set-attributes"
const el = document.getElementById("sample");
setAttributes(el, {"title": "タイトル"}); //title属性に"タイトル"を設定する
テストを書くための環境を整える
何はともあれ、npm init
から始めていきます。
作業ディレクトリに移動して、sample-test
ディレクトリを作成して初期化します。
$ mkdir sample-test && cd $_
$ npm init
とりあえず全部Enterしておきました。
それぞれのファイルを用意
とりあえず空の状態でモジュール、テスト用のファイルを作成しておきます。
$ mkdir test
$ touch set-attributes.js test/set-attributes.spec.js
ここまでで以下のような構成となっています。
.
├── package.json
├── set-attributes.js #モジュール用のファイル
└── test
└── set-attributes.spec.js #テスト用のファイル
karmaのインストールと設定
テストを走らせるために、まずはkarma
をインストールしていきます。
$ npm install --save-dev karma
インストールが終わったら、設定ファイルを作ります。
karma init
を実行すると、対話形式で設定ファイルを作ることができます。 わぁ便利っ!
$ ./node_modules/.bin/karma init
それぞれの質問に対して、上下+Enter
などのキーボード操作で回答していきます。
Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> mocha
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
Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> PhantomJS
>
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.
>
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.
>
Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes
Config file generated at "/path/to/set-attributes/karma.conf.js".
これで、karma.conf.js
の雛形が生成されました。
テストを実施するブラウザですが、TravisCI
上で簡単に動かしたかったのでPhantomJS
としていますが、Chrome
やFirefox
などお好みのブラウザで大丈夫なはずです。 (TravisCI
でChrome
などのブラウザも動かせるようですが、いちいち設定するよりPhantomJS
の方が手軽なので 笑)
ここまでで設定ファイルの生成と同時に、mocha
+PhantomJS
のインストールまで行ってくれています!
最低限の準備が出来たので、package.json
のscripts
を以下のように書き換えて、npm test
を実行した時にテストが走るようにしておきます。
{
// ...省略
"scripts": {
"test": "karma start"
},
// ...省略
}
power-assert周りのライブラリをインストール
アサーションにpower-assert
、import/export
を使うことになるのでbrowserify
も含め、いくつかのライブラリをインストールします。
$ npm install --save-dev babel-plugin-espower babelify@6.4.0 karma-browserify power-assert
インストールしたのは以下。
※babelifyのバージョンに注意
この記事を書いた時点(2015.11.2)で気をつけないといけなかった点がbabelify
のバージョンです。
6.x
系にしないとテストを走らせた時に、以下の様なTypeError
が出てしまいます。
TypeError: undefined is not a function while parsing file: /path/to/set-attributes/test/set-attributes.spec.js
詳しくは調べられていないのですが、babel
本体の6.x
でのプラグインAPI変更の影響のようでした。
ただ、プラグイン側の対応が追いつけば気にしなくても平気そうです。
karma.conf.jsを編集
インストールしたbrowserify
やpower-assert
など設定していきます。
コメントアウトや、空行を削除していますがベースは最初に作った雛形のままです。
module.exports = function(config) {
config.set({
basePath: "",
frameworks: ["mocha", "browserify"], //"browserify"を追加
files: [
"test/**/*.spec.js" //テストコード用のファイル
],
exclude: [],
preprocessors: {
"test/**/*.spec.js": "browserify" //frameworkと同じく
},
// browserifyの設定
browserify: {
debug: true,
transform: [
["babelify", {plugins: ["babel-plugin-espower"]}]
]
},
reporters: ["progress"],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ["PhantomJS"],
singleRun: false,
concurrency: Infinity
})
}
ここまででとりあえず、テスト自体が走るかどうかを確認しておきたいので、./test/scrollable-elements.js
に以下の様なテストを書きます。
import assert from "power-assert"
describe("テストの実行", () => {
it("1+1は2であるべき!", () => {
assert(1 + 1 === 3);
});
});
明らかに失敗するテストですね。
そしたら、これを実行してみます。
$ npm test
テストの実行 1+1は2であるべき! FAILED
AssertionError: # test/set-attributes.spec.js:5
assert(1 + 1 === 3)
| |
2 false
[number] 3
=> 3
[number] 1 + 1
=> 2
power-assert
の親切な画面に出会えました…!
そもそもちゃんとテストを書く習慣がなかったので、power-assert
は今回初めて使ったのですが、噂通りすっっっごく分かりやすかったです。
細かいアサーションメソッドを覚えなくても、これ以上無いくらい分かりやすくメッセージを返してくれるところに惚れ惚れでした。
DOMテスト用にライブラリをインストール
基本的なテストの準備整いましたが、このままだとDOM
に関するテストには不十分そうです。
テストコードとは別にfixture
(HTML
)を用意して書いていきたいので、必要なライブラリと設定を行っていきます。
$ npm install --save-dev karma-fixture karma-html2js-preprocessor
インストールしたのは以下。
インストールが終わったら、fixture
用のディレクトリとファイルを作っておきます。
$ mkdir test/fixtures
$ touch test/fixtures/set-attributes.html
fixtures
の中にある.html
をmocha
へ渡すために、karma.conf.js
を編集します。
module.exports = function(config) {
config.set({
basePath: "",
frameworks: ["mocha", "browserify", "fixture"], //"fixture"を追加
files: [
"test/fixtures/**/*.html", //.htmlへのパスを追加
"test/**/*.spec.js"
],
exclude: [],
preprocessors: {
"test/**/*.html": "html2js",
"test/**/*.spec.js": "browserify"
},
// ...省略
})
}
こうすることで、mocha
のテスト内で次のように、window.__html__["HTMLへのパス"]
で、HTML
の内容を文字列で取得できます。
console.log( window.__html__["test/fixtures/set-attributes.html"] ); //...set-attributes.htmlの中身
テストを書く!
テストを書く前にset-attributes.js
に空の関数だけ定義しておきます。
export default function setAttributes() {}
test/fixtures/set-attributes.html
にはHTML
を用意しておきます。
<div id="sample"></div>
そしたら、test/set-attributes.spec.js
にテストを書いていきます。
import assert from "power-assert"
import setAttributes from "../set-attributes"
describe("setAttributes()", () => {
// fixturesのHTMLを描画
before(() => {
document.body.innerHTML = window.__html__["test/fixtures/set-attributes.html"];
});
// HTMLをクリアしておく
after(() => {
document.body.innerHTML = "";
});
it("指定した属性値が適用される", () => {
const el = document.getElementById("sample");
setAttributes(el, {
"class": "test",
"title": "サンプル"
});
assert(el.getAttribute("class") === "test");
assert(el.getAttribute("title") === "サンプル");
});
});
ここで、テストが通らないことを確認してみます。
$ npm test
AssertionError
がエラーが出ればOKですね。
テストの監視が続いているので、次はモジュールの実装をしてみます。
モジュールの実装
set-attributes.js
に空の状態で定義していたsetAttributes
関数を実装します。
export default function setAttributes(el, params = {}) {
Object.keys(params).forEach((key) => {
const value = params[key];
el.setAttribute(key, value);
});
}
ファイルを保存すると、自動でテストが再実行されます。
以下のようにSUCCESS
が表示されたら無事テストが通っています。 やった!
Executed 1 of 1 SUCCESS (0.009 secs / 0.001 secs)
おまけ
ちょいちょい書き足すやりかたで書いてきましたので、設定ファイルや構成など一通り書いておきます。
最終的なファイル構成
.
├── karma.conf.js
├── node_modules
├── package.json
├── set-attributes.js
└── test
├── fixtures
└── set-attributes.spec.js
karma.conf.js
module.exports = function(config) {
config.set({
basePath: "",
frameworks: ["mocha", "browserify", "fixture"],
files: [
"test/fixtures/**/*.html",
"test/**/*.spec.js"
],
exclude: [],
preprocessors: {
"test/**/*.html": "html2js",
"test/**/*.spec.js": "browserify"
},
browserify: {
debug: true,
transform: [
["babelify", {plugins: ["babel-plugin-espower"]}]
]
},
reporters: ["progress"],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ["PhantomJS"],
singleRun: false,
concurrency: Infinity
})
}
package.json
{
"name": "sample-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "karma start"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-plugin-espower": "^1.0.0",
"babelify": "^6.4.0",
"karma": "^0.13.14",
"karma-browserify": "^4.4.0",
"karma-fixture": "^0.2.5",
"karma-html2js-preprocessor": "^0.1.0",
"karma-mocha": "^0.2.0",
"karma-phantomjs-launcher": "^0.2.1",
"mocha": "^2.3.3",
"phantomjs": "^1.9.18",
"power-assert": "^1.1.0"
}
}
参考サイト
さいごに
ここまでやってきて、一回設定すればあまり難しくなく始められそうだし、今更ではありますが、これからは少しずつテストを書くことを習慣化していきたいと思いました。
全然関係ありませんが、来週開催される東京Node学園祭2015に参加します。Node学園自体が初めてなのですごく楽しみっ!
Comments