概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: How to Test Multiple WebSocket Sessions With Minitest and Rails 5 System Tests
- 原文公開日: 2017/12/17
- 著者: Kieran Eglin
- サイト: https://kierancodes.com/
Rails 5: WebSocketのマルチセッションをMiniTestとシステムテストでテストする(翻訳)
状況
やりとりにWebSocketを使うチャットアプリがあり、サブスクライブ先のソケットをディクテーションするためのログインシステムがあるとします。通常のシステムテストを使って、メッセージが往復していることを確認するにはどうしたらよいでしょうか?
MiniTestと、Capybaraを使うRails 5のシステムテストが前提です。
最初にやってみたこと
Capybaraのopen_new_window
を使って新しいブラウザタブを開き、そこでサインインして操作します。within_window
でタブ間を切り替えることもできます。
これは一見うまくいきそうに見えますが、何人かのユーザーがsocketにサブスクライブする方法によっては、タブのオープン/サインアウト/新しいユーザーとしてログインしてメッセージを送信するなどのアプリ操作がごちゃごちゃになってしまいそうです。それに、このやり方は本質的に何か間違っているのではないかと思えてきませんか。
今回の解決法
実はCabpybaraのセッションを複数作成して、それらを切り替えることができるのです。
セッションを1つ作成すると新規ウィンドウが1つ初期化され、cookieやローカルストレージなどが完全に他と分離されます。この方法はすっきりしていますし、「より正しい」ソリューションのように思えます。なお、このデフォルトセッション名は、よりによって:default
です。セッション名の取得や設定はCapybara.session_name
で行えます。
以下はこれを行うためのテストコード例です。
test 'チャットルームのメッセージがリアルタイムで更新される' do
login_as @bob
visit '/chatroom'
Capybara.session_name = :new_window # この名前はまったく自由に設定できます
# ここからは完全に新しいブラウザセッションです!
login_as @sue
visit '/chatroom'
submit_message 'Hey, Bob!'
Capybara.session_name = :default # ここから元のBobのセッションに戻ります
assert page.has_content?('Hey, Bob!')
私にはこっちの方がずっとよさそうに思えますし、実際しっかり動きます。
しかしこの書き方はいくらなんでも見苦しすぎます。
もう少しコードを減らして読みやすくしたい場合、私はtest_helper.rb
に置いている次のシンプルなメソッドみたいな方法が好きです。
def within_session(name)
old_session_name = Capybara.session_name
Capybara.session_name = name.to_sym
yield
Capybara.session_name = old_session_name
end
これを使って、先ほどのテストを以下のように簡潔に書けます。
test 'Chatroom messages update in real time' do
login_as @bob
visit '/chatroom'
within_session :new_window do
login_as @sue
visit '/chatroom'
submit_message 'Hey, Bob!'
end
assert page.has_content?('Hey, Bob!')
これでさらによくなったと思いませんか?
クリーンアップ
最後に、テストスイート実行完了後に新規ブラウザウィンドウが開きっぱなしになっていることがあります。問題というほとのものではありませんが、やはり好きになれません。以下のような方法でウィンドウを簡単に閉じられます。
def close_session(name, original_session = :default)
Capybara.session_name = name.to_sym
page.driver.quit
Capybara.session_name = original_session
end
次のように、テストの終わったウィンドウに対して使うこともできます。
close_session :new_window
Happy coding!