I'm trying to broadcast to a different channel in my app but I can not get it to work. Also I trying to write a test but I'm not sure how.
From what I can gather I succeed in broadcasting the message from the notification_channel but it's not received in chat_channel.
Notification should send to chat.
notification_channel.ex
  def handle_in("new:group:recommendation", msg, socket) do
    payload = %{
        message: msg["message"],
        url: msg["url"],
        title: msg["title"],
        user_name: get_name_of_user(socket.assigns.user_grapqhl_id),
        user_grapqhl_id: socket.assigns.user_grapqhl_id
    }
    IO.puts "incomming"
    IO.inspect msg
    Enum.map(msg["groups"], fn(x) ->
        App.Endpoint.broadcast_from! self(), "chat:"<>x,
            "new:recommendation", payload
        end)
    {:reply, :ok, socket}
  end
chat_channel.ex
 def handle_in("new:recommendation", msg, socket) do
      IO.puts "i am a recommendation !"
      IO.inspect msg
      chat_msg = %{
         "creator_id" => msg["user_grapqhl_id"],
         "text" => msg["message"],
         "creator_name" => msg["user_name"]
      }
     broadcast! socket, "new:msg", create_chat_msg(chat_msg,socket)
     {:reply, :ok, socket}
  end
test
  test "do we send a new:recommendation to chat ?", %{guardian_token: guardian_token} do
      nils_base_64 = Base.encode64("user:nils")
      {:ok, socket} = connect(UserSocket, %{})
      {:ok, _, socket1} = subscribe_and_join(socket, "notifications:"<>nils_base_64, %{"guardian_token" => guardian_token})
      {:ok, _, socket} = subscribe_and_join(socket1, "chat:Y2hhdDpjaGF0Mw==", %{"guardian_token" => guardian_token})
      payload = %{
          "message" => "look at this cool thing!",
          "url" => "link to stuff",
          "title" => "AWESOME EVENT",
          "groups" => ["Y2hhdDpjaGF0Mw==", "Y2hhdDpwdWJsaWM="]
      }
      reply = %{message: "look at this cool thing!", title: "AWESOME EVENT", url: "link to stuff", user_grapqhl_id: nils_base_64, user_name: "Nils Eriksson"}
      ref = push socket1, "new:group:recommendation", payload
      assert_reply ref, :ok
      assert_broadcast "new:recommendation", ^reply
  end
This test passes and i can get it to fail by changing the reply
or commenting out the broadcast. I can not get it to fail by changing the handle_in to receive fail:please in chat_channel. 
That is something that it would complain on if i would send change this 
ref = push socket1, "new:group:recommendation", payload 
to ref = push socket, "new:group:recommendation", payload not supprising in that case. 
This is what is on the wire.
     Process mailbox:
   %Phoenix.Socket.Message{event: "init:msgs", payload: %{messages: []}, ref: nil, topic: "chat:Y2hhdDpjaGF0Mw=="}
   %Phoenix.Socket.Broadcast{event: "new:recommendation", payload: %{message: "look at this cool thing!", title: "AWESOME EVENTs", url: "link to stuff", user_grapqhl_id: "dXNlcjpuaWxz", user_name: "Nils Eriksson"}, topic: "chat:Y2hhdDpjaGF0Mw=="}
   %Phoenix.Socket.Message{event: "new:recommendation", payload: %{message: "look at this cool thing!", title: "AWESOME EVENTs", url: "link to stuff", user_grapqhl_id: "dXNlcjpuaWxz", user_name: "Nils Eriksson"}, ref: nil, topic: "chat:Y2hhdDpjaGF0Mw=="}
I use channel authentication since the elm package i use does not support authentication on socket level yet. so this is what it looks like in chat
  def join("chat:" <> chat_id, %{"guardian_token" => token}, socket) do
  IO.puts chat_id
  case sign_in(socket, token) do
     {:ok, authed_socket, _guardian_params} ->
         Process.flag(:trap_exit, true)
         send(self, {:after_join})
         [_type, node_chat_id] = Node.from_global_id(chat_id)
         {:ok, assign(authed_socket, :chat_id, node_chat_id)}
     {:error, reason} ->
         IO.puts "Can't join channel cuz: " <> reason
       # handle error TODO
   end
end
Since you use broadcast_from/4 from your Endpoint.You should use handle_info/2 in your chat_channel:
alias Phoenix.Socket.Broadcast
  ...
def handle_info(%Broadcast{topic: _, event: ev, payload: payload}, socket) do
    IO.puts ev
    IO.inspect payload
    # do something with ev and payload( push or broadcast)
    {:noreply, socket}
  end
Or you can listen that event from your client:
chatChannel.on("new:recommendation", resp => {
   // doSomething with response
}
Edit:
Let's explain a bit about how the channel and PubSub system work.
When you want to broadcast or push an event with payload.First it will send to the PubSub system and then the PubSub system will send it to all the subscriber process (channel) with the topic that channel registered itself with the PubSub system.
And when you use Endpoint.broadcast_from/4 to broadcast an event from your server.The PubSub system will receive an event with payload and broadcast that event to the topic that channel registered.
The channel will trigger handle_out callback and push the message to the client.
So in your chat_channel you don't need to handle_in "new:recommendation" event.Your client just need to listen to that event.
chatChannel.on("new:recommendation", resp => {
   // do something with response
}
And let me rewrite your test:
setup do
    nils_base_64 = Base.encode64("user:nils")
    {:ok, socket} = connect(UserSocket, %{})
    {:ok, _, socket} = subscribe_and_join(socket, "notifications:"<>nils_base_64, %{"guardian_token" => guardian_token})
    {:ok, socket: socket}
  end
test "do we send a new:recommendation to chat ?", %{socket: socket} do
      MyApp.Endpoint.subscribe("chat:Y2hhdDpjaGF0Mw==")
      payload = %{
          "message" => "look at this cool thing!",
          "url" => "link to stuff",
          "title" => "AWESOME EVENT",
          "groups" => ["Y2hhdDpjaGF0Mw==", "Y2hhdDpwdWJsaWM="]
      }
      reply = %Phoenix.Socket.Broadcast{message: "look at this cool thing!",
              title: "AWESOME EVENT",
              url: "link to stuff",
              user_grapqhl_id: nils_base_64,
              user_name: "Nils Eriksson"}
      ref = push socket, "new:group:recommendation", payload
      assert_reply ref, :ok
      assert_receive ^reply
  end
By subscribe to the topic that you want to listen you can make sure that your channel is received the message with assert_receive.
That is the way to test broadcast to a different channel.
Give it a try and tell me.The test will pass.
Use App.Endpoint.broadcast topic, event, payload with the topic of your chat channel. It should work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With