dream icon indicating copy to clipboard operation
dream copied to clipboard

How to test requests and websockets? [depends on Dream client]

Open tcoopman opened this issue 4 years ago • 5 comments

Is there any recommended way or documentation on how to tests controllers and websockets?

I could use external tools, for example connect to the server with javascript and initiate websockets there, but it would be nice if we could do this from ocaml directly and use dune to run the tests

tcoopman avatar Jun 30 '21 08:06 tcoopman

There is some (not much) support for in-process no-network testing, see section Testing. In particular, Dream.request can be used to artificially create a request, and then Dream.test runs it through a web app. Dream's own unit test suite (highly incomplete; I've been relying on the examples so far) uses this. For example, see this helper used to define most of the router tests:

https://github.com/aantron/dream/blob/500f4d0d37e5b0dcc4d4283ef5a36f2226c6caea/test/expect/middleware/router.ml#L83-L99

These are expect tests, so they just print to STDOUT/STDERR, and ppx_expect compares them with correct output.

There is nothing else besides that, but I do have a notes item to look into this. I'd appreciate it very much if you would let me know what type of testing you'd like to do, and/or provide me with a link to some implementation of it (in JS or elsewhere). I'd then see how it should be supported in Dream or at least in OCaml.

There is nothing for testing WebSockets conveniently at the moment, a definite gap. To test them immediately, you'd need to do end-to-end tests with an external tool.

aantron avatar Jun 30 '21 15:06 aantron

There is nothing for testing WebSockets conveniently at the moment, a definite gap. To test them immediately, you'd need to do end-to-end tests with an external tool.

That's what I was thinking about and what I was afraid of... Basically what I would want is to be able to start a Dream.websocket in a test and be able to connect clients to it.

I know how to do it with external tools, but it's a bit of overhead and not as fun as being able to do directly.

For other tests, I like the phoenix tests (https://hexdocs.pm/phoenix/testing_controllers.html) For example:

describe "index" do
  test "lists all posts", %{conn: conn} do
    conn = get(conn, Routes.post_path(conn, :index))
    assert html_response(conn, 200) =~ "Listing Posts"
  end
end

(I don't think =~ is something ppx_expect can do)

They also have nice tests for websockets:

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

  %{socket: socket}
end

test "ping replies with status ok", %{socket: socket} do
  ref = push(socket, "ping", %{"hello" => "there"})
  assert_reply ref, :ok, %{"hello" => "there"}
end

Of course this is not for a general websocket connection, but you get the point.

tcoopman avatar Jun 30 '21 17:06 tcoopman

Another example:

If I want to write a unit test around something that manages the current clients connected to websockets (Dream.websocket), I see no way of creating these Dream.websockets in a test contest.

tcoopman avatar Jul 02 '21 13:07 tcoopman

I started creating Hyper last year, the client counterpart to Dream. It likely can address parts of this issue.

aantron avatar Apr 27 '23 12:04 aantron

In particular, the client's requesting functions are request -> response promise functions, and a Dream Web app has the same type signature (before it is passed to Dream.run/Dream.serve). One of Hyper's test suites, nohttp, implements the server by directly calling the server function. Of course, there are tests with actual HTTP transports as well.

I expect this would eventually be useful for the users' Dream (and Hyper) testing.

aantron avatar Apr 27 '23 12:04 aantron