Post

Javascript処理を挟むテストの場合、Capybaraを待たせる必要

状況

ローカルや本番で問題なく動いているけど、RSpec テストが通ったり、通れなかったりする状況があった。

test log を確認したところ、個別 example の動きがおかしくなったりしている。

1
2
3
Started POST "/questions/1/answer?result=good" for 127.0.0.1 at 2022-09-02 23:25:25 +0900
Processing by QuestionsController#answer as TURBO_STREAM
  Parameters: {"result"=>"good", "id"=>"1"}

ここは、/questions/2/answer へ遷移すべきだけど、なぜか controller が受け取ったparams[:id]1になっている

そのせいで、テストが失敗したかもと推測。 なんで parameter が正確に送られていないだろう、その原因が分からなくて、一時詰まってた。

原因

チームメンバと相談して、ようやくテストが失敗する原因を特定できた。 Rails 7 はデフォルトで ajax で画面遷移を行なっているため、たまに capybara が ajax 処理が完了するまで待たなくて、前の画面でテストを先に処理してしまった。そのせいで、前の画面で取得したオブジェクト ID を controller に送ってしまった。

対策

次の画面操作する前に、capybara をちょっとだけ待たせることで、テストが問題なく通った。 capybara を待たせる方法は主に二つあるそうで、

  • sleepを使って、capybara を一時停止させる
1
2
3
click_on '次の質問'
sleep 1   # capybaraを1秒間sleepさせる
click_on '次の操作ボタン'
  • ただsleepを大量使用する場合、テスト実行効率が非常に悪くなるので、 代わりにfindhave_xx句を使って、遷移後の画面にあるべき要素を確認する処理を入れることで、capybara が自動的に画面遷移の処理が完了するまで待ってくれる。 デフォルトの待ち時間が最大 2 秒。

とにかくsleepさせるよりは、二つ目の方がより賢い。

1
2
3
click_on '次の質問'
expect(page).to have_content "次の画面タイトル"
click_on '次の操作ボタン'

参照:
テストが失敗する場合は sleep 等でテストを停止させてみる
RSpec の sleep 処理について

This post is licensed under CC BY 4.0 by the author.