こんにちは丸山@h13i32maruです。
ES6でアプリコード、テストコードを書いてテストをするための環境を作ったので、そのメモです。
目標
- ES6で書いたアプリコードとテストコードを
npm run test
でテストする
最終的な環境
最終的にはこんな環境になった。リポジトリ
- ECMAScript6
- Google Chrome
- Travis CI
- npm
- traceur-compiler
- mocha
- espower-cli
- karma
- karma-cli
- karma-mocha
- karma-chrome-launcher
- bower
- power-assert
今回はgrunt/gulpのようなビルドシステムは入れていない。npm run
をタスク実行のフロントとすることでタスク自体はお手軽にshで書いた。shだとwindowsが厳しいけど、まあとりあえず自分の環境用だしいいかなと。
以降ではこの環境を作っていく方法を順を追ってメモ。
- Step0: nodejsとnpmの環境を作る
- Step1: ES6 + traceurの環境を作る
- Step2: mocha + power-assertの環境作る
- Step3: karmaの環境作る
- Step4: Travis CIの環境作る
Step0: nodejsとnpmの環境を作る
目標: 「JavaScriptのパッケージ管理システムをセットアップする」
- nodejs
- JavaScriptの実行環境
node hello.js
みたいにしてJavaScriptを実行する
- npm
- nodejsの上に構築されているJavaScriptのパッケージ管理システム
npm install foo-bar
みたいにしてパッケージをインストールする
nodejsはHomeBrewで入れるか、サイトからバイナリ落としてきて入れればOK。npmはnodejs入れれば一緒に入るはず。
Step1: ES6 + traceurの環境を作る
目標: 「ES6で書いたJavaScriptをtraceurでコンパイルしてブラウザで動作確認する」
- ECMAScript6
- 次世代のJavaScript仕様
- 仕様やその策定についてはmozilla、YoheiM.NETあたりをみるとよい
- traceur
- ES6をES5にコンパイルしてくれるトランスパイラ
- ES6の全機能を使えるわけじゃないのでLanguageFeaturesを見ると良い
- 実際にES6を書くにはES6の基礎知識、traceur-compiler入門、ES6 modulesあたりを読むと良い
ファイル構成
├── package.json ├── script │ └── build.sh └── src ├── foo.js ├── hello.js ├── index.html └── main.js
package.json
package.json
はnpm
で使用するファイル。プロジェクトローカルで必要なパッケージやタスクの定義をしておくことができる。npm init
で対話的にひな形を作ることが可能。ただのjsonファイルなので自分で書いても良い。各プロパティについてはここが参考になる。traceur-compiler
もnpm
でインストールできるのでdependencies
プロパティに書いておく。それとnpm run task-name
としてタスクも実行できる(make
みたいなもの)のでtraceur-compiler
によるコンパイルタスクもscripts
プロパティに定義しておく。
{ "name": "js-test-sample", "version": "1.0.0", "description": "javascript unit test sample project", "scripts": { "build": "bash ./script/build.sh" }, "license": "MIT", "dependencies": { "traceur": "" } }
script/build.sh
package.json
のなかでbuild
タスクを定義したので、そのタスクの実態(traceur-compiler
によるコンパイル)。grunt
やgulp
で実装するのがモダンぽいけど、数行のshでできるので今回は手抜き。
#!/bin/bash ./node_modules/.bin/traceur --out build/src/all.js src/main.js
src/*.js
ES6で書かれたアプリケーションコード。
// src/main.js import Hello from './hello'; import Foo from './foo'; var hello = new Hello('bob'); console.log(hello.say()); var foo = new Foo('abc'); console.log(foo.echo());
// src/hello.js export default class Hello { constructor(name) { this.name = name; } say() { return `hello ${this.name}`; } }
// src/foo.js export default class Foo { constructor(str) { this.str = str; } echo() { return this.str; } }
src/index.html
アプリケーションを動かすHTML。traceur-compiler
でコンパイルしたコードはtraceur-runtime.js
が無いと動かないので一緒に読み込む必要がある。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="../node_modules/traceur/bin/traceur-runtime.js"></script> <script src="../build/src/all.js"></script> </head> <body> </body> </html>
動作確認
各ファイルを作成したら必要なパッケージを入れてビルドする。
npm install # package.jsonのdependenciesに書いてあるパッケージがインストールされる npm run build # ES6 → ES5へコンパイルされてbuild/src/all.jsが作られる
無事にビルドできたらsrc/index.html
をブラウザで見ればOK。コンソールにhello bob
とか出てれば成功。
Step2: mocha + power-assertの環境作る
目標: 「mocha + power-assertでテストを書いてブラウザで実行する」
- mocha
- テストフレームワーク
- assertionは内蔵していないので別途入れて使う
- power-assert
- nodejsのassert互換のassertionライブラリ
- assert失敗時に賢いログを出してくれる
- espower-cli
- power-assertを使うにはテストコードをespower-cliを通してpower-assert用のコードに変換する必要がある*1
- Bower
- パッケージ管理システム
- npmがもともとnodejs用のパッケージ管理システムとして開発されたのに対して、Bowerはブラウザで使うJavaScript用のパッケージ管理システムとして開発されている*2
- npmと同じように
bower.json
というファイルを書いてそこに必要なパッケージなどを書いていく
ファイル構成
├── bower.json ├── package.json ├── script │ ├── build.sh │ └── test_browser.sh ├── src │ ├── foo.js │ ├── hello.js │ ├── index.html │ └── main.js └── test ├── foo_test.js ├── hello_test.js └── index.html
bower.json
プロジェクトローカルで必要なBowerのパッケージを定義しておく。npmのpackage.jsonと同じように使える。ブラウザで使うようのpower-assertはBowerのパッケージとして提供されている*3。
{ "name": "js-test", "version": "0.0.0", "license": "MIT", "dependencies": { "power-assert": "" } }
package.json
mochaとespower-cliが必要になったのでpackage.jsonに追加する。それとnpm run test_browser
でテストが実行されるようにタスクも追加。
{ "name": "js-test-sample", "version": "1.0.0", "description": "javascript unit test sample project", "scripts": { "build": "bash ./script/build.sh", "test_browser": "bash ./script/test_browser.sh" }, "license": "MIT", "dependencies": { "traceur": "", "mocha": "", "espower-cli": "" } }
script/test_brwoser.sh
package.json
のなかでtest_browser
タスクを定義したので、そのタスクの実態。テストコードもES6で書くのでtraceurでコンパイルする。コンパイルできたall_test.js
をpower-assert用のコードに変換してespowered_all_test.js
を作る。これがテストコードになる。あとはそれを読み込ませたtest/index.html
をブラウザで開けばテストが走る。
#!/bin/bash ./node_modules/.bin/traceur --out build/test/all_test.js $(find test/ -name '*_test.js') ./node_modules/.bin/espower build/test/all_test.js > build/test/espowered_all_test.js open -a 'Google Chrome' test/index.html
test/*_test.js
テストコードもES6で書く。
// test/hello_test.js import Hello from '../src/hello'; describe('Hello', ()=>{ it('says hello', ()=>{ let name = 'bob'; let hello = new Hello(name); let message = `hello ${name}`; assert.equal(hello.say(), message); }) });
// test/foo_test.js import Foo from '../src/foo'; describe('Foo', ()=>{ it('echos str', ()=>{ let str = 'abc'; let foo = new Foo(str); assert.equal(foo.echo(), str); }) });
test/index.html
mocha, power-assert, テストコードを読み込んでブラウザでテストを行うためのHTMLファイル。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Mocha Tests</title> <link rel="stylesheet" href="../node_modules/mocha/mocha.css" /> </head> <body> <div id="mocha"></div> <script src="../node_modules/traceur/bin/traceur-runtime.js"></script> <script src="../bower_components/power-assert/build/power-assert.js"></script> <script src="../node_modules/mocha/mocha.js"></script> <script>mocha.setup('bdd')</script> <script src="../build/test/espowered_all_test.js"></script> <script> mocha.checkLeaks(); mocha.run(); </script> </body> </html>
動作確認
まずはBowerをグローバルな領域にインストールする。
npm install -g bower
次に追加のパッケージを入れてテストを走らせる。
npm install # mocha, espower-cliがインストールされる bower install # power-asserがインストールされる npm run test_browser # テストが実行される
Google Chromeが起動してテスト完了の画面が表示されれば成功。
Step3: karmaの環境作る
目標: 「karmaを使ってCLIからテスト結果を確認できるようにする」
- karma
- テストコードをブラウザで実行して結果をCLIに表示してくれるテストランナー
- テストフレームワークはmocha, jasmine, QUnitなどを別途使う
- ブラウザはChrome, Safari, Firefox, Phantomjs(ヘッドレスブラウザ)などを使える
- karma-mocha
- karmaでmochaを使うためのプラグイン
- karma-chrome-launcher
- karmaでGoogle Chromeを使うためのプラグイン
- karma-cli
- karmaをCLIから使うためのプラグイン
ファイル構成
├── bower.json ├── package.json ├── script │ ├── build.sh │ ├── test_browser.sh │ └── test_karma.sh ├── src │ ├── foo.js │ ├── hello.js │ ├── index.html │ └── main.js └── test ├── foo_test.js ├── hello_test.js ├── index.html └── karma.conf.js
package.json
karma関連のパッケージを追加。それとnpm run test
でkarmaによるテストが走るようにタスクも追加。
{ "name": "js-test-sample", "version": "1.0.0", "description": "javascript unit test sample project", "scripts": { "build": "bash ./script/build.sh", "test_browser": "bash ./script/test_browser.sh", "test": "bash ./script/test_karma.sh" }, "license": "MIT", "dependencies": { "traceur": "", "mocha": "", "espower-cli": "", "karma": "", "karma-mocha": "", "karma-chrome-launcher": "", "karma-cli": "" } }
script/test_karma.sh
package.json
のなかでtest
タスクを定義したので、そのタスクの実態。基本的にはscript/test_browser.sh
と同じだが、テストの実行方法がkarmaを使うようになっている。
#!/bin/bash ./node_modules/.bin/traceur --out build/test/all_test.js $(find test/ -name '*_test.js') ./node_modules/.bin/espower build/test/all_test.js > build/test/espowered_all_test.js ./node_modules/.bin/karma start test/karma.conf.js
test/karma.conf.js
karmaの設定ファイル。Step2でGoogle Chromeでテストをするときにtest/index.html
にmocha, power-assertなどを書いていたのをkarmaを使う場合はこの設定ファイルに書くイメージ。各プロパティの詳細はここを見る。
module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha'], files: [ 'node_modules/traceur/bin/traceur-runtime.js', 'bower_components/power-assert/build/power-assert.js', 'build/test/espowered_all_test.js' ], reporters: ['progress'], port: 9876, colors: true, logLevel: config.LOG_INFO, browsers: ['Chrome'], singleRun: true }); };
動作確認
各ファイルを作成したら追加のパッケージをインストールしてテストを走らせる。
npm install # karma関連がインストールされる npm run test # karmaを使ったテストが実行される
コンソールにテスト結果が表示されれば成功。
補足
はじめはPhantomJSでテストを実行しようとしたんだけど、traceurが吐き出すコードがPhantomJSで動かなかった。traceurを使うにはES5が動く環境が必要なんだけど、PhantomJSはES5に対応してない部分があるみたい。es5-shimとかも入れてみたんだけどダメだったので、まあテストする環境はなるべく本番に近いほうが良いしChromeでいいかなということにした。
Step4: Travis CIの環境作る
目標: 「コードをプッシュしたらTravis CIでテストを実行される」
- Travis CI
- GitHubと連携したCIサービス
ファイル構成
├── bower.json ├── package.json ├── script │ ├── build.sh │ ├── test_browser.sh │ └── test_karma.sh ├── src │ ├── foo.js │ ├── hello.js │ ├── index.html │ └── main.js └── test ├── .travis.yml ├── foo_test.js ├── hello_test.js ├── index.html └── karma.conf.js
.travis.yml
Travis CIは連携しているGitHubのリポジトリにコードがプッシュされるのを検知した後、リポジトリに含まれる.travis.yaml
というファイルに基づいてテストを行う。今回はJSのテスト環境なのでここを見て設定ファイルを書く。設定したコードがいつ動くかのライフサイクルはここを見る。
今回はChromeを使ってテストをする必要があるので、その設定をbefore_install
に書いておく必要がる。まずGUIなアプリを動かすにはここにかかれているようにDISPLAY
とxvfb
を設定する必要がある。それだけどFirefoxでしかテストできないようなので、CHROME_BIN
という環境変数を設定することでkarmaがChromeを実行できるようになる。けどTravis上でChromeを使う方法が公式ドキュメントを探しても見つからなくて、stackoverflowやkarma issueで見つけた。公式ドキュメントに書いておいて欲しい。。
それとTravis上で実行されていることが判定できるようにenv
プロパティにTRAVIS
を設定した。
language: node_js node_js: - "0.10" script: npm run test env: - TRAVIS=1 before_install: - export CHROME_BIN=chromium-browser - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - npm install -g bower install: - npm install - bower install
script/test_karma.sh
Travis上でテストを行うときは少しだけkarmaの実行方法を変える必要がある。具体的にはChromeの起動オプションを変える。--browsers ChromeTravis
オプションはTravisように起動をプションを追加したChromeで実行するように指定するもの。実態はkarma.conf.js
に書いてある。
#!/bin/bash ./node_modules/.bin/traceur --out build/test/all_test.js $(find test/ -name '*_test.js') ./node_modules/.bin/espower build/test/all_test.js > build/test/espowered_all_test.js if [ -n "$TRAVIS" ] then ./node_modules/.bin/karma start test/karma.conf.js --browsers ChromeTravis else ./node_modules/.bin/karma start test/karma.conf.js fi
test/karma.conf.js
Travis上でChromeを動かすにはChromeの起動オプションを変更する必要があるので、それようにcustomLaunchers
という設定を追加する。
module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha'], files: [ 'node_modules/traceur/bin/traceur-runtime.js', 'bower_components/power-assert/build/power-assert.js', 'build/test/espowered_all_test.js' ], reporters: ['progress'], port: 9876, colors: true, logLevel: config.LOG_INFO, browsers: ['Chrome'], singleRun: true, customLaunchers: { ChromeTravis: { base: 'Chrome', flags: ['--no-sandbox'] } } }); };
動作確認
各ファイルを作成したらTravis上でテストを走らせる。事前にTravisにログインしてリポジトリの連携をしておく必要がある。あと、初回のpushではテストが動いてくれなかったので適当にダミーをコミットしてpushして動かしてみた。
感想
めちゃ大変だった。個々のツールはそんなに難しくないけど、それぞれをどうやって結びつけるかとか、ドキュメントが色んなサイトにまたがってたりとか。以前にもES5 + jasmine + karma + PhantomJS + travisで作ったことがあったけど、こういう環境構築ってプロジェクト始める一番最初しからやらないのですぐに忘れてしまう。だから今回はまた作ることがあっても思い出せるように順をおってメモしてみた。
あと足らないのはminifyぐらいか。grunt/gulpはshが複雑になってきてから移行を考えよう。使うツールはなるべく少なくしたいし。watchはWebStorm頼みということで。