おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

Capybara 2.0 アップグレードガイド

Capybara 2.0 Upgrade Guide - Funding Gates の意訳です。

capybara の 2.0.0 beta がリリースされたらしく、上記エントリでは重要な変更点とアップグレードの仕方について解説してくれています。

good news と bad news

  • 2.0.0 にアップグレードしたら、現在のテストが一部通らなくなるかもしれなません
  • 一度 2.0.0 でテストが通るようになったら、そのまま 1.1.2 に戻すことも出来ます。まだ 2.0.0 が肌に合わないようならまだ切り戻すことができます。

互換性

capybara-webkitpoltergeist はまだ Capybara 2.0 に対応していません。ひとまず selenium ドライバを使いましょう。

How to Upgrade

2.0.0 beta は約一ヶ月前にリリースされました。beta よりも master ブランチを使うのをオススメします。

group :test do
  gem 'capybara', git: 'https://github.com/jnicklas/capybara'
end

これまでのテストを壊す可能性のある箇所が二つあります。data-method と 曖昧なマッチです。一つずつ紹介していきます。

“data-method” はデフォルトでは無効

(2012/8/30追記) pull request が取り込まれたので、capybara 2.0.0 では下記の記述は無効となりました。Capybara 2.0.0 でも 1.1.2 と同様の挙動をします。

デフォルトの RackTest ドライバ(js: true としなければ使われます)は、設定しない限り data-method 属性を無視するようになりました。 例えば、下記のようなリンクがあったとします

= link_to "Delete", article_path(@article), method: :delete

Capybara 1.1.2 では、 `click_on 'Delete'` は JavaScript が必要なのに関わらずうまくいきますが、Capybara 2.0.0 では :respect_data_method を有効にしないとそのような挙動にはなりません。

require 'capybara/rails'
require 'capybara/rspec'

# Override default rack_test driver to respect data-method attributes.
Capybara.register_driver :rack_test do |app|
  Capybara::RackTest::Driver.new(app, :respect_data_method => true)
end

このエントリの著者([@jo_liss](https://twitter.com/jo_liss))が Issue を上げているので、 2.0.0 のリリース時には :respect_data_method の設定は必要なくなっているかも。

Pull Request #793: Make :respect_data_method default to true with capybara/rails by joliss · jnicklas/capybara

曖昧マッチ

find メソッドは、一つ以上の要素が見つかったときにエラーを発生させるようになりました。( click_onfill_in なども同じ)

Capybara 1.1.2 では、単純に最初にマッチした要素が選択されますが、現在は曖昧さを排除しないといけません。

下記のコードはテストを壊す可能性がある例です。

fill_in 'Password', with: 'secret'
fill_in 'Password confirmation', with: 'secret'

2.0.0 では最初の fill_in は fail になります。理由は “Password” が “Password” のラベルと “Password confirmation” のラベルと両方にマッチするからです。つまり曖昧だからです。

これを直すには name 属性か id 属性に対してマッチさせるのがよいです。fill_in 'password', with: 'serect' のように。よい name や id がなかったら、補助として “.js-password” と “.js-password-confirmation” クラスを追加するとよいです。(“js-“ プレフィックスは Github styleguide で推奨されているクラスです)(追記: GitHub Styleguide は現在は404になっているようです><)

find('.js-password').set 'secret'
find('.js-password-confirmation').set 'secret'

“.js-“ クラスをテキストの代わりに使うことは、テストを壊れにくくするよいプラクティスです。

以前の挙動が絶対に必要であれば、first メソッドを使うとよいです。

click_on 'ambiguous' # old
first(:link, 'ambiguous').click # new

Minor changes

これらの変更はなにかおかしな事が無ければ、アップグレードしても影響しないと考えられます。

  • has_content? XPath の contains(...) を使わずに、 text の部分文字列をチェックします。これはつまりスペースの標準化と、headscript などの非表示要素抑制を改善します。
  • selectunselect は部分文字列のマッチを許可しなくなりました。
  • Capybara.server_boot_timeoutCapybara.prefer_visible_elements は必要なくなったので削除されました。
  • Capybara.timeoutwait_until は削除されました。。 Selenium ドライバの :resynchronize オプションも同様です。通常、page.should have_contentpage.should have_css で何らかのページ上の変化を探すためには、Ajax リクエストが返ってくるのを待たなければなりません。これらのチェックは Ajax リクエストに対して門のように振る舞い(訳注:Ajax と普通のリクエストの挙動を共通にさせるってことかな)、条件が真になるまで繰り返します。もしうまく動かないようなら、独自の wait_for ヘルパメソッドを定義することが出来ます(例: gist)
  • find(:my_id) のようなシンボルシンタックスはなくなるかもしれません。find('#my_id') が推奨されます。

Goodies

アップグレードしてもテストを壊さない、新しい追加要素がありますよ。

  • find(:field, '...') のような多くの新しいセレクタ。これらは複雑なノードを見つけるのに便利です。lib/capybara/selector.rb 中のadd_selector をチェックしてみましょう。
  • has_content? が正規表現を受け付けます。