(今更)RSpec2+Capybara-webkitでインテグレーションテスト

今回参考にさせてもらったところ。
っていうかほとんどそのまんま。

あのさみんな、Cucumberに関する情報が少なすぎると思わないかい。
胸熱なのはわかったよ、でも使い方を教えてくれよ。俺頭悪いからわからないよ。*1
というわけでCucumberはさっくり諦めてRSpec2をこれまで以上に愛していきます。

組み合わせは Ruby1.9.3, Rails3.2, Spork, autotest, RSpec2, Capybara-webkit, headless の7つ。
前半5つについては過去の記事を参照してもらうことにして、
今回はCapybara-webkitとheadlessでJavaScriptのテストを有効にするところまで。
※今回は実際にJavaScriptのコードはテストしません。有効にするだけです。

Gemfile:

gem 'spork'
gem 'rspec-rails'
gem 'capybara-webkit'
gem 'autotest-rails'
gem 'headless'

JavaScriptを含めたインテグレーションテストは capybara-webkit で完結するんですが、
テストを実行するたびにFirefoxを起動するのでいろいろと心臓に悪いです。
autotest を使っている身としては尚更です。

そこで headless ですよ。
これは端的に言えばXのDISPLAYをメモリ上に展開する Xvfb というライブラリのラッパーで、
capybara-webkit が起動するFirefoxには画面外で動作してもらおう、という力技。

まずはライブラリのほうをUbuntu流儀でインストールして、あとはいつものこと。

$ sudo apt-get install xvfb libqt4-dev
$ cd $RAILS_ROOT
$ bundle install
$ rails g rspec:install
$ spork --bootstrap

次に headless の設定。
黙っていてもcapybara-webkitがheadlessを使ってくれるように、
こちらは Spork 起動時に読み込んでもらうようにします。

spec/spec_helper.rb:

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However,
  # if you change any configuration or code from libraries loaded here, you'll
  # need to restart spork for it take effect.

  # ここから追加
  require "headless"
  headless = Headless.new(:display => 99)
  headless.start
  at_exit{ headless.destroy }
end

:display => 99 はネットで拾ってきた断片なのでよくわかりませんが、
とりあえずこれで動くのであまり触らないようにしておきます。

次はspecファイル。UsersControllerとかがあるとして、
spec/requests/users_spec.rb なんかにインテグレーションテストを記述します。
参考: GitHub - rspec/rspec-rails: RSpec for Rails-3+

githubrspec-rails より一部転載・改変。

describe "Users" do
  it "works" do
    get "/login"
    response.status.should be(200)
  end

  it "displays username after successful login" do
    user = Factory(:user, :username => "jdoe", :password => "secret")  # FactoryGirlを使う場合
    visit "/login"
    fill_in "Username", :with => "jdoe"
    fill_in "Password", :with => "secret"
    click_button "ログイン"

    page.should have_selector(".header .username", :text => "jdoe")
    page.should have_content("ログインしました")
  end

  context "when JavaScript used" do
    it "displays help dialog without redirect", :js => true do
      visit "/login"
      click_link "ヘルプ"
      page.should have_content("これはヘルプです")
    end
  end
end
end

have_selectorはjQueryなどでお馴染みのセレクタを使って要素を選択し、
残りの引数で属性をチェックできます。
have_contentは「ページのどっかに文字列があること」みたいです。

JavaScriptを使う場合、itディレクティブに対して明示的に :js => true を渡す必要があります。
このオプションが渡されたテストのみcapybara-webkit(=Firefox)が起動し、
どういう仕組みなのかよくわかりませんがテストを実行してくれるわけです。

headlessを使っている以上Firefoxのウィンドウは画面に表示されませんが、
裏ではしっかり起動されているのでそれなりに時間がかかるのが難点ですかね。
我慢できなかったら大人しく他のJavaScript処理系を使ったほうが良さそうです。
まだろくに試していないので何とも言えません……。

さて、あとは .autotest 作って .rspec に --drb とか追記して、

$ spork
$ autotest

ね? 簡単でしょ?

参考1: RSpec2 + Capybara-Webkitでの注意点 - === SANDmark 19106 === beginning stress test
参考2: SporkとRSpec2とautotestとCucumber+Capybara(webkit)とtwitter-bootstrap-railsを使うときのセットアップが長い - === SANDmark 19106 === beginning stress test

*1:正確にはたくさん情報はあるんだけど、1年前のものが大半なので2012年現在と結構違ったりする。