2011年11月 6日

Rspec Capybara_webkitを使ってjavascriptをテストする

Goal

ゴールと言うか目標はrspecのrequest(integration) testでjavascriptのテストをしたいです。が、いろいろハマってその問題と解決策を時間軸でメモしておきます。

Capybaraについてはある程度知ってる前提です。

javascriptのテストを書く

:js => trueでrspecのintegration testでjavascriptを有効に設定できます。
例:

# in your view erb file
<%= link_to_function "test js", '$(this).html("js works")' %>
# in test spec
it "supports js", :js => true do
visit tasks_path
click_link "test js"
page.should have_content("js works")
end

ただデフォルトではjavascriptをサポートしないので、このspecは失敗します。解決の鍵はcapybara driverというものです。

capybara_webkit driver

なぜcapybara_webkit driver使う

Capybara ... currently comes with Rack::Test and Selenium support built in.

By default, Capybara uses the :rack_test driver, which is fast but does not support JavaScript. You can set up a different default driver for your features.

The capybara-webkit driver is for true headless testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well. It is significantly faster than drivers like Selenium since it does not load an entire browser.

のようにcapybaraは Rack::TestSeleniumのdriverがbuilt-inされて、デフォルトdriverは前者の:rack_testでjavascriptをサポートしないです。Seleniumはサポートしますが、それよりも速いのがcapybara-webkitなのでそれを採用しました。

capybara_webkit driverをインストール

Gemfileにcapybara_webkitを追記、bundle installします。webkitはQTが必要なので、もしそれがないとbundle installで失敗(エラー)します。後はspec_helper.rbにdefault driverをwebkitに設定します。

# webkit-dependency
# if you don't have homebrew installed
/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"
# if you don't have QT installed
brew install qt
# Gemfile, add capybara-webkit
group :test, :development do
...
gem "capybara-webkit"
end
# in Terminal
bundle install
# set default capybara driver to webkit.
# I put this into spec_helper.rb
Capybara.javascript_driver = :webkit
# In RSpec, use the :js => true flag
it "supports js", :js => true do
...
end

これで最初のサンプルspecは通るはずです。

データベースと絡んだテスト

上記のままだとデータベースと絡んだテストはまた失敗します。
例:

it "displays tasks", :js => true do
Task.create!(:name => "foo")
visit tasks_path
click_link 'some link'
page.should have_content("some text")
end

自分で確認してみたら、テスト時に作成したデータはjavascriptのテストで使えないっぽいです。Railscastsの記事によりますとspecのテストではデータベーストランザクションを使うが、それがselenium或いはwebkitでは使えないそうです。そのためにdatabase_cleanerというgemを使います。

database_cleanerを使う

# in Gemfiile
group :test, :development do
...
gem "database_cleaner"
end
# in Terminal
bundle install
# in spec_helper.rb
RSpec.configure do |config|
# ...
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end

config.use_transactional_fixturesをfalseにした時点でもうテスト自体は通るはずですが、データはずっとそのまま残ってしまうんです。database_cleanerは名の通りデータベースをテスト前後で綺麗な状態に保つことができます。

これでもう環境面の設定は完了です!

Resources

Share on Twitter Share the post
Qihuan Piao

朴 起煥

東京で働いている「外人歴」9年のソフトウェア「ライター」。いつの間にか納豆が食えるようになり、これで日本に慣れきったと思いきやまだまだ驚きが続いてる。読んだり書いたりするのが好きで、自身の経験や本から得た「何か」をここに書き出してる。最近古本屋にハマってる。

他にも英語中国語で書いてます、よろしければチェックしてみてください。