TypeScript+Jasmine+PhantomJs+GuardでTDDしてみる
Ruby2.0の勉強そっちのけで、gem作ってました。。。
仕事でTypescript使ってjsのライブラリ的な物を作る事があるので、Jasmineでテスト書きながらTypeScriptコンパイルしてPhantomJsでテスト流す、という仕組みを、Guard使ってplugin作ってみた。github.com/yagince/guard-…
— なぎやつきさん (@yagince) 2013年4月14日
というわけで、仕事で使う為ではあったんですが、
勉強も兼ねて、
- TypeScriptとSpecの更新を監視
- TypeScirptが更新されたら更新したファイルのSpecを実行
- Specが更新されたら、テスト対象のTypeScriptファイルをコンパイルして、Spec実行
- Enter押したら全テスト実行
という、まさにguard-rspecがやってくれる事を、
Jasmineでもやりたいよ!と思って作りました。
Repository
動作確認済み環境
- Mac OSX 10.8.3
- Ubuntu 12.10
使い方
誠に勝手ではありますが、こいつは単体では動きません。。。
先にインストールしておく必要がある物があります。
- TypeScript (tscコマンドにPATHが通っている状態が必要)
- PhantomJs (phantomjsコマンドにPATHが通っている状態が必要)
順を追って使い方をメモしておきます。
TypeScriptのインストール
node.jsとnpmのインストールに関しては、
HomebrewでNode.js入れて、npmでCoffeeScriptを入れる - 成らぬは人の為さぬなりけり
こちらを参照して頂ければ良いかと。
※最新のnode.jsをbrewでインストールするとnpmのモジュールにPATH通らなかったような気も、、、
というわけで、npmさえインストールできていれば、
$ npm install typescript
で良いはずです。
PhantomJsのインストール
PhantomJsのインストールに関しては、
PhantomJs+Vert.x(JRuby)でSockJsの疎通確認をしてみる - 成らぬは人の為さぬなりけり
こちらを見ていただければ分かる通り。
$ brew install phantomjs
で完了です。(Macの場合のみですが、、、)
Linuxをお使いの方は、以下を参照してください。
PhantomJS: Download and Install
Gemfileの準備
bundlerでインストールする為に、Gemfileを準備します。
source 'https://rubygems.org' gem 'rb-fsevent' gem 'guard' gem 'guard-jasmine-phantomjs', :git => 'git://github.com/yagince/guard-jasmine-phantomjs.git'
「rb-fsevent」は無くても動くとおもいます。多分、、、。
リポジトリをcloneして、pathで指定してもOKです。
そして、bundlerでインストール。
$ bundle install --path vendor/bundle
Guard設定ファイルの準備
Guard用の設定ファイルはコマンドで生成できます。
$ bundle exec guard init
これで、ルートディレクトリに「Guardfile」が出来たとおもいます。
# A sample Guardfile # More info at https://github.com/guard/guard#readme guard :jasmine_phantomjs, { compile: :typescript, src_dir: 'src', spec_dir: 'spec', jasmine_version: '1.3.1', phantomjs: :gem # , out: 'src/all.js' # , root_script: 'src/root.ts' } do watch(%r{^src\/(.+?)\.ts$}) watch(%r{^spec/(.+?)\Spec.js$}){|m| "src/#{m[1]}.ts" } end
こんな感じになっているかと思います。
それぞれの設定に関しては、READMEを参照してください。
では、実際にこれを実行しておいて、ソースを書いていきます。
$ bundle exec guard 22:30:43 - INFO - Guard uses TerminalTitle to send notifications. 22:30:43 - INFO - Start jasmine-phantomjs. 22:30:43 - INFO - Start all script compile 22:30:44 - INFO - scripts compile finished. 22:30:44 - INFO - Guard is now watching at '/xxxx/workspace/typescript-samples/jasmine-test'
この時点で、tsファイルがあれば、全部コンパイルしてくれます。
Specを書く
ではspecを書いてみます。
spec/HogeSpec.js
describe("Hoge", function() { describe("#name", function() { it("should be return hoge", function() { expect(new Hoge().name()).toEqual('hoge'); }); }); });
保存するとテスト対象のファイルがコンパイルされます。
22:35:27 - INFO - Start compile ["src/Hoge.ts"] 22:35:27 - ERROR - Compile Error! Error reading file "src/Hoge.ts": File not found 22:35:27 - INFO - Start compile finished.
はい、まだテスト対象のファイルを作っていないので、not foundと怒られました。
テスト対象のソースを書く
では、テスト対象のソースを書いてみます。
src/Hoge.ts
class Hoge{ }
この時点で保存してみます。
22:38:21 - INFO - Start compile ["src/Hoge.ts"] 22:38:21 - INFO - Start compile finished. 22:38:21 - INFO - Start jasmine. 22:38:22 - INFO - Jasmine execute result. finished in 0.004s 1 examples, 1 failures Failures: 1) Hoge #name should be return hoge. TypeError: 'undefined' is not a function
コンパイルは通りました。
が、まだメソッドを実装していないので、テストはfailしています。
メソッドを実装する
では、メソッドを実装してみます。
class Hoge{ name(): string { return 'hoge'; } }
2:40:19 - INFO - Start compile ["src/Hoge.ts"] 22:40:19 - INFO - Start compile finished. 22:40:19 - INFO - Start jasmine. 22:40:20 - INFO - Jasmine execute result. finished in 0.004s 1 examples, 0 failures
テストも通りました。
Specが存在しないTypeScriptファイルを作ってみる
基本的には全て単体テスト書きたいですが、
どーしても書きづらかったりする時がたまーにあります。
なので、Specが存在しないtsファイルを作成、編集した場合どうなるかやってみます。
src/Foo.ts
class Foo { something(i: number): void { // do something... console.log(i); } }
22:45:28 - INFO - Start compile ["src/Foo.ts"] 22:45:29 - INFO - Start compile finished. 22:45:29 - INFO - Start jasmine.
「Start jasmine」と表示はされましたが、これはテストを実行していません。
※startって出てしまうのは、手抜きです、、、すみません。。。
specが存在しない場合はテストを実行しないようになっています。
SpecRunner.htmlのファイルの読み込み順序
今の状態だと、tsファイルを全て個別にコンパイルする状態になっており、
SpecRunner.htmlのscriptタグの順序も保証されません。
なので、読み込み順序をかっちりしたい場合は、
- out
- root_script
というオプションを使用してください。
まずは、
- out
このオプションを指定すると、「--out」オプションを付けてコンパイルします。
つまり、一個に纏めます。
- root_script
このオプションを指定すると、常に指定されたファイルのみをコンパイルします。
outオプションと併用する事で、
root_scriptオプションで指定したscriptから参照(reference path="")を辿って
tscが必要な物を全部コンパイルして、
一つのファイルにまとめてくれます。
今回のgemの使い方は以上です。
明日から、またRuby2.0やります。多分w