#feedback on websocket testing

1 messages · Page 1 of 1 (latest)

kindred tartan
#

.

#

in my mind the design is:

  1. caller (the test) starts websocket actor (the pseudo "client"),

  2. caller sends client messages to client which get sent over the network to the server,

  3. server responds and the reply triggers the client actor callback loop,

  4. in the callback loop, the server reply message gets forwarded to the caller so that they can assert on it or do whatever

kindred tartan
#
// server/test/client.gleam

pub opaque type Client {
  Client(
    self: Subject(stratus.InternalMessage(Message)),
    inbox: Subject(ServerMessage),
  )
}

pub opaque type Message {
  Send(ClientMessage)
  Close
}

type State {
  State(inbox: Subject(ServerMessage))
}

pub fn init() -> Result(Client, stratus.InitializationError) {
  let assert Ok(request) = request.to("http://localhost:8000/api/ws")
  let inbox = process.new_subject()

  stratus.new(request, State(inbox:))
  |> stratus.on_message(handle_message)
  |> stratus.on_close(handle_close)
  |> stratus.start
  |> result.map(fn(actor) { Client(self: actor.data, inbox:) })
}

pub fn send(client: Client, message: ClientMessage) -> Nil {
  process.send(client.self, message |> Send |> stratus.to_user_message)
}

pub fn close(client: Client) -> Nil {
  process.send(client.self, stratus.to_user_message(Close))
}

pub fn receive(client: Client) -> ServerMessage {
  process.receive_forever(client.inbox)
}

even better caller interface

#
// server/test/realtime_test.gleam

import client.{type Client}
import gleam/erlang/process.{type Subject}
import gleam/otp/actor
import server
import shared/transport.{type ServerMessage}

fn with_client(test_case: fn(Client) -> Nil) -> Nil {
  let assert Ok(actor.Started(pid: server, ..)) = server.init()
  let assert Ok(client) = client.init()
  test_case(client)
  client.close(client)
  process.send_exit(server)
}

pub fn receive_user_count_test() {
  use client <- with_client

  assert client.receive(client) == transport.UserCountUpdated(count: 1)
}

example test ends up looking something like this, the only issue is that i dont really know the "right" way to shut down the server once the test is done. im kind of cheating by sending an exit to the supervisor