Weird "argument error" in channel testing

I’ve run into a pretty weird error when trying to test channels. I’m only going to show the relevant code, so please let me know if you need more of it.

Basically, the setup method of the test module looks like this:

setup do
    {:ok, _, socket} =
      socket("user_id", %{some: :assign})
      #Subscribe to the "default" room so that we can send commands over events
      |> subscribe_and_join(RoomChannel, "default")
    {:ok, socket: socket}
  end

The point is, users by default are logged into the “default” room so that a connection is established and they can start creating and receiving events.

One such event is joining a room, for which my test is:

test "user can't join a room that doesn't exist" do
    # First, create user and app
    changeset = User.changeset(%User{})
    %User{id: user_id} = Repo.insert!(changeset)
    
    changeset = App.changeset(%App{})
    %App{id: app_id} = Repo.insert!(changeset)

    # pick invalid room id to join
    room_id = 13

    # attempt to join
    ref = push socket, "room", %{"command" => "join", "room_id" => room_id, "user_id" => user_id, "app_id" => app_id}
    assert_reply ref, :error, %{"reason" => "Room doesn't exist"}
  end

Here’s the function it calls in the channels module:

def handle_in("room", %{"command" => "join"} = data, socket) do
    {:reply, {:error, %{"reason" => "Room doesn't exist"}}, socket}
end

When I run the tests, I get the following error and I have no idea why:

  1) test user can't join a room that doesn't exist (Elemental.TxChat.RoomChannelTest)
     test/channels/room_channel_test.exs:83
     ** (ArgumentError) argument error
     stacktrace:
       :erlang.send(nil, %Phoenix.Socket.Message{event: "room", payload: %{"app_id" => 2, "command" => "join", "room_id" => 13, "user_id" => 2}, ref: #Reference<0.0.1.3003>, topic: nil})
       (phoenix) lib/phoenix/test/channel_test.ex:352: Phoenix.ChannelTest.push/3
       test/channels/room_channel_test.exs:95

Line 95 in the error message is the line that does the push socket stuff.

Now, I say it’s weird because another test that’s a perfect replica of this works fine:

test "on creating new rooms, users do not automatically join", %{socket: socket} do
    ref = push socket, "room", %{"command" => "create", "user_id" => 11, "app_id" => 11, "room_name" => "General chat"}
    assert_reply ref, :ok, %{"room_id" => room_id}
    
    room = Repo.get_by(Room, %{id: room_id})
    user = Repo.get_by(User, %{id: 11})

    user = Repo.preload user, :rooms
    assert user.rooms == [] # empty!    
  end

I’m just not able to understand why it should fail. Can anyone help me with some hints or maybe tell me what I’m doing wrong? Thanks in advance!

Your first test does not pattern match %{socket: socket} in its head.

1 Like

And that’s exactly why Elixir v1.4 warns if a variable becomes a function call. :smile:

I feel like such an idiot that I’m lost for words! :rage:

Hi, Jose. Thanks for helping me again. I’m not sure I understand, though. There was no warning in my case, at least from what I can make out. Also, could you please expand on how a variable can become a function? I’ve seen such error messages before (something like undefined function room_id) but if you could clarify with an example, that’ll be great!

In your case there was no variable socket, so it ended-up calling socket(). Elixir v1.4 (still unreleased) will warn if such happens.

You mean it ended up calling socket() without any arguments? If yes, then to me it appears to be a case of missing argument rather than a case of a variable becoming a function.

But leave it be, I guess. Perhaps I need to dive into macros to understand what you’re saying . . . :icon_sad:

Socket() with zero arguments is a separate function documented here: https://hexdocs.pm/phoenix/Phoenix.ChannelTest.html#socket/0