capybara-webkitとcucumberでjavascriptを使ったページのテストを行う

みなさん、cucumber使ってテスト書いてますか?最近はrspecユニットテストを書き、インテグレーションテストはcucumberを使う例が増えていると聞きます。
ここで問題になるのがjavascriptを含むページのテストです。色々情報を調べていたところ、capybara-webkitなるものをid:babieさんが使用しているのを発見。今回はcucumberで動かしてみました。

qtのインストール

capybara-webkitはqtというGUIフレームワークを使用しています。先にインストールしてしまいましょう。どちらの場合もコンパイルにめちゃくちゃ時間がかかるのでご注意を。

mac portsの人
$ sudo port install qt4-mac-devel
home brewの人
$ brew install qt

Gemfileの設定

適当にRailsプロジェクトを作成してGemfileの設定を行いましょう。

$ rails new experimental
$ cd experimental
$ vi Gemfile

Gemfileに次の内容を追記します。

group :development, :test do
  gem 'headless'
  gem 'cucumber'
  gem 'cucumber-rails'
  gem 'capybara-webkit'
  gem 'database_cleaner'
end

次のコマンドでインストールを行います。

$ bundle install

cucumberの初期化

次のコマンドでcucumberの実行に必要なフォルダやファイルを作成します。

$ rails g cucumber:install ja capybara

features/support/env.rbにwebkitを使用する設定を行います。

# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
# order to ease the transition to Capybara we set the default here. If you'd
# prefer to use XPath just remove this line and adjust any selectors in your
# steps to use the XPath syntax.
Capybara.default_selector = :css
Capybara.javascript_driver = :webkit #追加

あと、今回DBは使用しないけどschema.rbが無いと怒られるのでrake db:migrateしておきましょう。

$ rake db:migrate

Viewの作成

今回はjavascriptがテストできるかどうかの検証なので、簡単なViewのみ作成してみましょう。

$ rails g controller dummy

config/route.rbを変更してルーティングの設定を行いましょう。

Experimental::Application.routes.draw do
  resources :dummy
  #(略)
end

app/views/dummy/index.html.erb を作成し次の内容を記述します。

<div id="name"></div>
<a href="#" onclick="writeName();">click me</a>

<script type="text/javascript">
<!--
function writeName() {
  document.getElementById('name').innerHTML = 'ほむほむ';
}
// -->
</script>

これは簡単なjavascriptでclick meをクリックするとjavascriptで一部のhtmlを動的に書き換えています。

featuresの作成

それではfeatures/dummy.featuresにテストを書いてみましょう。

# language: ja

@javascript
フィーチャ: 名前を表示する
  名前を表示したい。
  なぜなら、ほむほむが好きだからだ。

  シナリオ: click meを押すとほむほむと表示される
    前提 "ダミー"ページを表示する
    もし "click me"リンクをクリックする
    ならば "ほむほむ"と表示されていること

javascriptを使うテストの場合は@javascriptタグを付けます。あと、このままでは"ダミー"ページがどこか分からないのでfeatures/support/paths.rbに記述しておきましょう。

  def path_to(page_name)
    case page_name

    when /^the home\s?page$/
      '/'
    when /^ダミー$/
      '/dummy'
    # (以下略)

テストの実行

次のコマンドで実行してみましょう。

$ bundle exec cucumber features/dummy.features

うまく動作すれば次のようなメッセージが表示されるはずです。

blossom:experimental kazuhisa$ bundle exec cucumber features/dummy.features 
Using the default profile...
# language: ja
@javascript
フィーチャ: 名前を表示する
  名前を表示したい。
  なぜなら、ほむほむが好きだからだ。

  シナリオ: clickmeを押すとほむほむと表示される # features/dummy.features:8
    前提"ダミー"ページを表示する           # features/step_definitions/web_steps_ja.rb:30
    もし"click me"リンクをクリックする    # features/step_definitions/web_steps_ja.rb:38
    ならば"ほむほむ"と表示されていること       # features/step_definitions/web_steps_ja.rb:100

1 scenario (1 passed)
3 steps (3 passed)
0m2.894s

今回はcucumberのみでテストを行いましたが、本来はrspecでモデル単位のユニットテストも記述するのが望ましいです。また、guardを使えば自動テストも行うことができます。
それでは良いテストライフを!