test-unitでのシステムテストでちょっとハマったのでメモ。
症状
テスト実行時にログイン処理が不安定(ログインできる/できない)という症状が発生。
class BooksTest < ApplicationSystemTestCase setup do @book = books(:one) # ログイン処理 visit root_url fill_in 'Eメール', with: 'alice@example.com' fill_in 'パスワード', with: 'password' click_on 'ログイン' end test 'visiting the index' do visit books_url assert_selector 'h1', text: 'Books' # ここでテストがパスしない end end
原因
Railsアプリが描画処理にTurboを使用しており、JavaScriptの描画処理(画面遷移)の完了を待たずにCapybaraが動作してしまうため。
- テスト検証のタイミングに描画処理の完了が間に合っていない(テストのフライング)
- Turboに限らず、Ajaxでの非同期処理でも発生するらしい
- ブラウザによってはパスすることもあるっぽい
対策
assert_xxx
系のメソッドでJavaScriptの描画処理の完了を待たせる。
assert_text
、assert_selector
等が使える- デフォルトで最大2秒待ってくれる
class BooksTest < ApplicationSystemTestCase setup do @book = books(:one) # ログイン処理 visit root_url fill_in 'Eメール', with: 'alice@example.com' fill_in 'パスワード', with: 'password' click_on 'ログイン' assert_text 'ログインしました。' # JavaScriptの処理完了を待たせる end test 'visiting the index' do visit books_url assert_selector 'h1', text: 'Books' # JavaScriptの処理完了後に実行される end end
その他の対策
sleep
を使って処理を待たせる- テスト実行が遅くなるので微妙かも...
- Turboの無効化
- アプリ自体の描画処理が遅くなるっぽい
- React、Vue等では対策できない
感想
久々に時間溶かしてしまった... システムテストは描画処理の完了と検証開始のタイミングは必ずしも一致していないことに注意していこう。