2014年5月9日金曜日

Capybara で一時的に非同期処理の待ち時間を調整する

Ruby で開発している Web アプリのテストを強力に支援してくれる Capybara。デフォルトで非同期処理のテストにも対応してまして、特定の要素を見つけ出したり、条件に一致する要素の存在確認をしたりするテストにおいて、失敗した場合に一定時間(デフォルトでは2秒間)待ち、再度DOMを読み直してテストを再実行する機能が組み込まれております。

これは便利な機能ですが、しかし非同期処理を想定しないテストの時も、毎回レッドのたびに2秒待たされるのも無駄です。この非同期処理の待ち時間を変更する方法の1つは、using_wait_time メソッドを使うことです。

using_wait_time 1 do
  expect(page).to have_css '#hoge'
end

上記コードは非同期処理の待ち時間を1秒に設定してブロック内のテストを実行します。

あるいは、Capybara 2.1以降なら find メソッドにおいて :wait オプションが使えます。Capybara 2.2以降なら、matcher系メソッド(have_cssなど)でも :wait オプションが使えます。

expect(page).to have_css('#hoge', :wait => 1)

上記コードは先程載せた using_wait_time の使用例と同じく、非同期処理の待ち時間を1秒に設定してテストを実行できます。

ここで、Cucmuberとの組み合わせの例を示しておこうと思います。僕が実際使っているステップ定義の一部を紹介しましょう。

ならば(/^".*?\((.*?)\)" に "(.*?)" と表示(?:され|されていること)(\(非同期\))?( debug)?$/) do |t_css, t_text, t_async, debug|
  show_debug_info if debug
  target_node = page.find(t_css, :text => t_text, :visible => true, :wait => t_async ? async_time : 0)
  expect(target_node.text).to eq(t_text)
end

def async_time
  Capybara.default_wait_time
end

def show_debug_info
  puts page.response_headers
  puts page.status_code
  puts page.current_url
  puts page.html
end

上記のステップ定義において、末尾に (非同期) という文字列をつけると非同期処理の待ち時間をデフォルト(2秒)にし、付けない場合は0秒すなわち待たない設定としています。例えば、非同期処理を待たない場合はこんなふうになります。

ならば "ログイン名(#login-name)" に "admin" と表示されていること

ここで、もし非同期通信を待ちたければ、

ならば "ログイン名(#login-name)" に "admin" と表示されていること(非同期)

と書けばいいです。

ちなみに、このステップの実行直前にデバッグ情報を表示させたければ

ならば "ログイン名(#login-name)" に "admin" と表示されていること debug

と書けばできるようにしています。

正規表現によるステップ定義は高い柔軟性をもたせられるのが利点ですね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

0 件のコメント:

コメントを投稿