How to assert the websocket status code on tests?

I would like to make a test to assert if specific status codes were used when a websocket connection is closed.

In my code, I raise {:stop, :normal, {1009, "message-too-big"}, :init}, {:stop, :normal, {1007, "invalid-json"}, :init}, {:stop, :normal, {4000, "missing-required-field"}, :init} and others.

When I interact in websocket using wscat:

wscat -c ws://localhost:4000/v1/ws
(I provoke an error resulting in a connection closed by server)

I get the closed connection messages as:

Disconnected (code: 1007, reason: "invalid-json")

My test would be something like that:

  test "sends a invalid JSON" do
    assert {:ok, client} = WebsocketClient.connect(self(), @path, :noop)
    WebsocketClient.send(client, {:text, '{"foo": "bar", something_wrong_here}')})
    
   # assert if the connection was closed with status code 1007 and reason invalid-json
  end

How could I write the status code and reason asserts?

What is WebsocketClient? I couldn’t find anything with a similar API in any of the likely hits for “websocket” on hex.pm.


As far as the specifics of an assertion, I find it useful to assert clearly-wrong things first and then let the failure messages clue me into what’s going on. For instance:

result = do_something_complicated(etc etc etc)

assert result == "foo"

Running a spec like this and seeing the assert fail produces several important pieces of data:

  • demonstrates that do_something_complicated at least runs (important when the setup is tricky)

  • inspects result in the failure message

1 Like

I am sorry. Missing information: Websocketclient is my class to abstract GenServer lib:

  def connect(sender, url, serializer, headers \\ []) do
    with {:ok, socket} <- GenServer.start_link(__MODULE__, {sender, serializer}),
         {:ok, :connected} <- GenServer.call(socket, {:connect, url, headers}) do
      {:ok, socket}
    end
  end

  def send(socket, msg) do
    GenServer.call(socket, {:send, msg})
  end

About the test itself, in the example, I want to send a bad formated JSON message, since something_wrong_here is not inside quotation marks and is not a key/value, it is a invalid structure in JSON:

{"foo": "bar", something_wrong_here}

My application is intolerant to client errors, so, the behaviour is immediately do a disconnection. There is no message sent back, only the disconnection. I want to test if the client was disconnected and if the correct status code and reason for disconnection were sent (using the websocket protocol). I expect to get the same message shown when I make this call using the wscat command line:

Disconnected (code: 1007, reason: "invalid-json")

I do not know how to get this “disconnection” state and data.

This part of the code gives a little bit of information about what might happen. The implementation of send tells me that the test will be waiting for a reply.

HOWEVER

It tells nothing else about what might happen when the connection malfunctions. Does the handle_call({:send, msg} handler crash (and cause the test to exit as well)? Does it reply with {:error, ????}? Something else entirely?

I close connection from server returning a {:stop, :normal, {result["code"], result["msg"]}, :init} from handle_in function like this:

defmodule MyApp.Websocket do
  @behaviour Phoenix.Socket.Transport
  ...
  def handle_in({input, _opts}, state) do
      result  = ...
      result_text = ...
      ...
      case result["type"] do
        "error" -> {:stop, :normal, {result["code"], result["msg"]}, :init}
        _ -> {:reply, :ok, {:text, result_text}, new_state}
      end
    end
end