Error about no socket supervision tree in tests

Hi, I’m trying to write a test for a channel and am confused by the way the test is failing.

My test:

defmodule MusicJamServerWeb.RoomChannelTest do
  use MusicJamServerWeb.ChannelCase

  setup do
    {:ok, _, socket} =
      UserSocket
      |> socket("user_id", %{some: :assign})
      |> subscribe_and_join(MusicJamServerWeb.RoomChannel, "room:lobby")

    %{socket: socket}
  end

  test "broadcasts instrument updates to room:{id}", %{socket: socket} do
    push(socket, "update_instrument", %{"body" => "muzak"})
    assert_broadcast "update_instrument", %{"body" => "muzak"}
  end
end

My ChannelCase module, where I reference the endpoint:

defmodule MusicJamServerWeb.ChannelCase do
  use ExUnit.CaseTemplate

  using do
    quote do
      # Import conveniences for testing with channels
      import Phoenix.ChannelTest

      # The default endpoint for testing
      @endpoint MusicJamServerWeb.Endpoint
    end
  end

  setup _tags do
  #   pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Demo.Repo, shared: not tags[:async])
  #   on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
    :ok
  end
end

And in my Endpoint module, I declare a socket mount like so:

defmodule MusicJamServerWeb.Endpoint do

  ...

  socket "/socket", MusicJamServerWeb.UserSocket,
    websocket: true,
    longpoll: false

  ...

end

Yet the test fails because it thinks Endpoint does not contain a socket mount?

1) test broadcasts instrument updates to room:{id} (MusicJamServerWeb.RoomChannelTest)
     test/music_jam_server_web/channels/room_channel_test.exs:14
     ** (ArgumentError) no socket supervision tree found for UserSocket.
     
     Ensure your MusicJamServerWeb.Endpoint contains a socket mount, for example:
     
         socket "/socket", UserSocket,
           websocket: true,
           longpoll: true

Can you show your application.ex file, as well as how you are running your tests?

Hi @patreeceeo, error is that you are not providing correct module name for socket in test setup. It should be

setup do
    {:ok, _, socket} =
      MusicJamServerWeb.UserSocket
      |> socket("user_id", %{some: :assign})
      |> subscribe_and_join(MusicJamServerWeb.RoomChannel, "room:lobby")

    %{socket: socket}
  end

:+1:
2 Likes

Thanks! can’t believe I didn’t see that. I guess I should brush up on how modules work in Elixir, I’m surprised there wasn’t an error about UserSocket being undefined.

You’re welcome! :raised_hands:

Okay, read everything in the guides about modules (Modules and functions - The Elixir programming language, alias, require, and import - The Elixir programming language) not seeing anything that sheds light on why the error I got in the above situation was just about a lack of a socket mount, and not about the lack of the module altogether. I guess in Elixir/Erlang, any alias (e.g. Empty) can be used as a module, and if there’s no corresponding defmodules it’s equivalent to defmodule Empty do ... end?

Almost. When you reference a module in code, you’re just using an atom. There is no compile time check that the module exists with that atom as its name, because the dynamic nature of the BEAM allows for the construction or loading of modules at runtime.