Ruby(Rack + bundler)のwebアプリケーションでJavaScript部分をTDDで開発する環境を整えてみたので、作業メモを晒してみる。

今回はブラウザを使ったテストなので、GUI環境上に構築していく。

環境

  • Mac OS X 10.7.4
  • Ruby 1.9.3-p0
  • rvm 1.9.2
  • Xcode 4.3.2

Jasmineの準備

インストール
  • Gemfile
gem "jasmine", :group => "test"
$ bundle install
イニシャライズ
$ bundle exec jasmine init

サンプルとなるJavaScriptとテストケースが自動生成される。

$ tree public/javascripts/ spec/javascripts/
public/javascripts/
├── Player.js
└── Song.js
spec/javascripts/
├── PlayerSpec.js
├── helpers
│  └── SpecHelper.js
└── support
    └── jasmine.yml

RakefileにもJasmineのタスクが追加される。

  • Rakefile
begin
  require 'jasmine'
  load 'jasmine/tasks/jasmine.rake'
rescue LoadError
  task :jasmine do
    abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
  end
end
動作確認

rake jasmineを実行すると、8888番ポートでWEBrickが起動する。

$ bundle exec rake jasmine
your tests are here:
  http://localhost:8888/
[2012-05-24 11:11:35] INFO  WEBrick 1.3.1
[2012-05-24 11:11:35] INFO  ruby 1.9.3 (2012-04-20) [x86_64-darwin11.3.0]
[2012-05-24 11:11:35] INFO  WEBrick::HTTPServer#start: pid=16256 port=8888

ブラウザで http://localhost:8888/ にアクセスすると、サンプルとして用意されたPlayerSpec.jsに書かれたテストケースが走り、Player.jsをテストした結果を表示する。

guard-livereloadの準備

いちいちブラウザをリロードするのは面倒なので、guard-livereloadを使ってファイルの変更を監視し検知したらブラウザを自動リロードする、という仕組みも準備してみる。

インストール

  • Gemfile
gem 'guard-livereload', :group => "test"
% bundle install
 # (snip)
make
compiling binder.cpp
make: g++-4.2: No such file or directory
 # (snip)

g++-4.2 がないというエラーが出たので乱暴に解決。 /usr/bin/g++-4.2/usr/bin/g++ のSymLinkとして作成する。

% which g++-4.2
g++-4.2 not found
% which g++
/usr/bin/g++
% sudo ln -s /usr/bin/g++ /usr/bin/g++-4.2
% which g++-4.2
/usr/bin/g++-4.2

続き。

% bundle exec guard init livereload
Writing new Guardfile to /{project_root}/Guardfile
livereload guard added to Guardfile, feel free to edit it

変更を監視するファイルの設定

アプリケーションのルートにGuardfileが生成されている。

  • Guardfile

Jasmineに関連するファイルだけを監視対象にする。

guard 'livereload' do
  watch(%r{public/.+\.js})
  watch(%r{spec/javascripts/.+\.js})
end

実はこのままだと「JasmineによるTDD」はうまく動かない(後述)。

ブラウザエクステンションをインストール

LiveReload 1.xはDeprecatedらしいが、LiveReload 2は$9.99なのでとりあえず見送り。旧ドキュメントを参考に、利用するブラウザのエクステンションをインストールしておく。

https://github.com/mockko/livereload/blob/master/README-old.md

guard-livereloadを起動

% bundle exec guard
Guard could not detect any of the supported notification libraries.
Guard is now watching at '/{project_root}/'
LiveReload 1.6 is waiting for a browser to connect.

最初の行が気になるが、まずはLiveReloadがブラウザの監視を始めたようだ。

Safariの場合は

% bundle exec rake jasmine

でJasmineを起動しておいてブラウザで http://localhost:8888/ にアクセス。ページを右クリックして「Enable LiveReload」を選ぶ。

Browser connected.
Browser URL: http://localhost:8888/

リロードされない場合の対処

これでJavaScriptファイルが更新されるとブラウザがリロードされるはず。しかし別のターミナルから…

% touch path/to/your.js

などとすると、guardのコンソールに…

Reloading browser: path/to/your.js

とは出るのだが、ブラウザはリロードされない。

livereloadのREADMEによると…

# reload the whole page when .js changes
config.apply_js_live = false

apply_js_liveをfalseに設定すれば、JSの更新でページ全体をリロードしてくれるらしい。trueの場合は更新されたJavaScriptだけをリロードするので、Jasmineのテストは走らない。

この設定はGuardfileの引数として記述する、とドキュメントに書いてある

Available options:
  (snip)
:apply_js_live => false  # default true

ということでGuardfileを書き換えて、guardを再起動する。

guard 'livereload', :apply_js_live => false do
  watch(%r{public/.+\.js})
  watch(%r{spec/javascripts/.+\.js})
end
% touch path/to/your.js

ブラウザが自動でリロードされただろうか。

今までずっと先送りにしてきたJavaScriptの単体テスト環境をやっと整えた。次はCIに組み込むべくjasmine-headless-webkitを導入したい。