Rails 5: WebSocketのマルチセッションをMiniTestとシステムテストでテストする(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

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!

関連記事

Rails 5.1以降のシステムテストをRSpecで実行する(翻訳)

TestProf: Ruby/Railsの遅いテストを診断するgem(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ