mmag

ハマったことメモなど

Phoenix.ChannelTestでどのsocketに対するpushか区別する

例えば特定のchannelに2人が接続したらそれぞれに違うメッセージをpushするような何かを考える。

socketsocket/1socket/3でつくってsubscribe_and_join/4すればテスト上でjoinまでできる。ただしassert_push/3は引数にsocketを与えられないので、2人のどちらに送られたものか判別できない。

なにか方法はないかIO.inspect socketとかアレコレやっていると、join_refというのが使えそうに見える。

assert_pushの実装は以下のようになっていて

defmacro assert_push(event, payload, timeout \\ Application.fetch_env!(:ex_unit, :assert_receive_timeout)) do
  quote do
    assert_receive %Phoenix.Socket.Message{event: unquote(event), payload: unquote(payload)}, unquote(timeout)
  end
end

実体はassert_receiveなので、これを使うと

# 1人目
{:ok, socket} = UserSocket.connect(%{"user_id" => "u1"}, socket(UserSocket), %{})
{:ok, _, %{join_ref: join_ref1}} = socket |> subscribe_and_join(ChatChannel, "room:1", %{})

# 2人目
{:ok, socket} = UserSocket.connect(%{"user_id" => "u2"}, socket(UserSocket), %{})
{:ok, _, %{join_ref: join_ref2}} = socket |> subscribe_and_join(ChatChannel, "room:1", %{})

# 1人目に"hey", 2人目に"hello"
assert_receive %Phoenix.Socket.Message{event: "hey", payload: %{}, join_ref: ^join_ref1}
assert_receive %Phoenix.Socket.Message{event: "hello", payload: %{}, join_ref: ^join_ref2}

と書ける。パターンマッチなので^を忘れずに。