テストでWebsocketのsubscribeが終わるまで待ちたい

  1. ページを開く
  2. ActionCableのブロードキャストを実行する
  3. ブロードキャストの結果画面が変更されるのを確認する

というテストがあるときに、2がActionCableの該当チャンネルのsubscribeより前に実行されてしまいテストが失敗する、という事象があった。

なのでsubscribeを待つためのヘルパーメソッドを書いてみた。asyncアダプタ想定で、subscriber情報を持っているハッシュの個数が0より大きくなればsubscribe完了しているだろう、と判断した。

  def wait_for_websocket_connection
    Timeout.timeout(Capybara.default_max_wait_time) do
      until ActionCable.server.pubsub.send(:subscriber_map).instance_variable_get(:@subscribers).count > 0
        sleep 0.5
      end
    end
  end

だいぶナイーブな実装なのでうまく動かないケースもありそうだけど、とりあえずこれで。

2024/02/06追記

ActionCableへの購読は、まず内部用のチャンネル(ActionCable::Connection::InternalChannel) を購読してから専用のチャンネルを購読する、という流れになるので、上記のコードだとタイミングによってはまだチャンネルの購読が完了していない事がある。そこを次のようなコードで改善してみた。しばらくこれで様子見

  # `stream_for current_user ` のようにして購読している前提

  def wait_for_websocket_connection(user)
    channel = NotificationChannel.broadcasting_for(user)
    block = lambda do
      s = ActionCable.server.pubsub.send(:subscriber_map).instance_variable_get(:@subscribers)
      s.key?(channel) && s[channel].count > 0
    end

    Timeout.timeout(Capybara.default_max_wait_time) do
      sleep 0.5 until block.call
    end
  end