Unit testing websocket endpoint issue

Hello!
I’m trying to add some unit tests for a websocket endpoint (Endpoint[Unit, Long, String, Pipe[IO, Request, Response], Any with Fs2Streams[IO] with WebSockets]). However, when I try to test connecting to the websocket endpoint I get back a Internal server error and in the logs I see

Exception when handling request: GET /external/async/video, by: GET /external/async/video, took: 30ms
java.lang.ClassCastException: class com.service.endpoints.VideoStreamApi$$Lambda$959/0x0000000800882840 cannot be cast to class scala.runtime.Nothing$ (com.service.endpoints.VideoStreamApi$$Lambda$959/0x0000000800882840 and scala.runtime.Nothing$ are in unnamed module of loader 'app')
	at sttp.tapir.server.stub.SttpResponseEncoder$$anon$1.fromWebSocketPipe(SttpResponseEncoder.scala:28)
	at sttp.tapir.server.interpreter.EncodeOutputs.$anonfun$applySingle$7(EncodeOutputs.scala:62)
	at sttp.tapir.server.interpreter.ServerInterpreter$$anon$3.apply(ServerInterpreter.scala:229)
	at sttp.tapir.server.interpreter.ServerInterpreter$$anon$2.$anonfun$onDecodeSuccess$2(ServerInterpreter.scala:204)
	at map @ sttp.client3.impl.cats.CatsMonadError.map(CatsMonadError.scala:9)
	at flatMap @ sttp.client3.impl.cats.CatsMonadError.flatMap(CatsMonadError.scala:12)
	at flatMap @ sttp.client3.impl.cats.CatsMonadError.flatMap(CatsMonadError.scala:12)
	at recoverWith @ sttp.client3.impl.cats.CatsMonadError.handleWrappedError(CatsMonadError.scala:17)
	at recoverWith @ sttp.client3.impl.cats.CatsMonadError.handleWrappedError(CatsMonadError.scala:17)
	at map @ sttp.client3.impl.cats.CatsMonadError.map(CatsMonadError.scala:9)

This is the code for the test, I was just trying to establish a connection to the websocket endpoint:

val sttpStub: SttpBackendStub[IO, Any with Fs2Streams[IO] with WebSockets] = AsyncHttpClientFs2Backend
    .stub[IO]

private val backendStub = TapirStubInterpreter(, stub = sttpStub)
    .whenServerEndpointsRunLogic(videoStreamAPIStub.endpoints)
    .backend()

val response = basicRequest
    .get(uri"https://test.com/external/async/video")
    .header("X-As-Member-Id", memberId.toString)
    .response(asWebSocketAlways[IO, Any](_ => IO.unit))
    .send(backendStub)

This test follows the same pattern as my HTTP request unit tests so I’m wondering if I’m doing something wrong with the way I’m trying to test the websocket? Or could this be something that isn’t fully supported by websockets?

I’m afraid websocket streams (websockets in tapir are always streamed) aren’t supported by the stub, see: tapir/server/sttp-stub-server/src/main/scala/sttp/tapir/server/stub/SttpResponseEncoder.scala at aa91771a7a54709153f417acced08928c1ec349d · softwaremill/tapir · GitHub

They also aren’t supported by sttp: [FEATURE] Stub for testing websocket stream · Issue #1493 · softwaremill/sttp · GitHub

We might be able to fix this first in sttp4, then in tapir, but it’s nothing immediate. As a work-around, I think you should be able to test the pipe in isolation (not perfect, but always something :slight_smile: )

1 Like