elysiajs / eden

Fully type-safe Elysia client
MIT License
147 stars 37 forks source link

Using `treaty` with an Elysia instance does not allow connecting to WebSockets #88

Open Lykhant opened 4 months ago

Lykhant commented 4 months ago

Environment

Platform

Linux, Nobara 39 (Fedora derivative)

Tool versions

Bun version: 1.1.4 Elysia version: 1.0.12 Eden version: 1.0.14

How to reproduce

/src/index.ts

import { Elysia, t } from 'elysia'
import { treaty } from '@elysiajs/eden'

const app = new Elysia()
    .ws('/chat', {
        body: t.String(),
        response: t.String(),
        message(ws, message) {
            ws.send(message)
        }
    })
    .listen(3000)

/test/index.test.ts

import { test, expect } from "bun:test";
import { treaty } from "@elysiajs/eden";
import { app } from "../src/index";

const api = treaty(app);

test("Websocket", async () => {
  const chat = api.chat.subscribe();
  await new Promise<void>((resolve) => {
    chat.addEventListener("open", () => resolve());
  });

  let messages: string[] = [];
  chat.subscribe((message) => {
    messages.push(message.data);
  });

  chat.send("hello from client");
  await new Promise<void>((resolve) => {
    chat.addEventListener("message", () => resolve(), { once: true });
  });
  expect(messages).toEqual(["hello from client"]);
});

Running bun test in this state causes the following:

bun test v1.1.4 (fbe2fe0c)

test/index.test.ts:
error: Test "Websocket" timed out after 5000ms
✗ Websocket [5000.65ms]

 0 pass
 1 fail
Ran 1 tests across 1 files. [5.09s]

However, when changing line 5 to const api = treaty<typeof app>("localhost:3000") and start up the server with bun dev before running the test, the test passes:

bun test v1.1.4 (fbe2fe0c)

test/index.test.ts:
✓ Websocket [10.22ms]

 1 pass
 0 fail
 1 expect() calls
Ran 1 tests across 1 files. [33.00ms]
mrctrifork commented 4 months ago

To test your code with websockets you'd have to run the server.

Have you tried reshaping your test as follows?


test('WebSocket / works', (done) => {
  app.listen(8080, () => {
    // Now the server is ready and your test can run

    // Finish the test
    done()
  })
})
Lykhant commented 4 months ago

Same result, the test times out.

import { test, expect } from "bun:test";
import { treaty } from "@elysiajs/eden";
import { app } from "../src/index";

const api = treaty(app);

test("Websocket with instance", async (done) => {
  app.listen(8080, async () => {
    const chat = api.chat.subscribe();
    await new Promise<void>((resolve) => {
      chat.addEventListener("open", () => resolve());
    });

    let messages: string[] = [];
    chat.subscribe((message) => {
      messages.push(message.data);
    });

    chat.send("hello from client");
    await new Promise<void>((resolve) => {
      chat.addEventListener("message", () => resolve(), { once: true });
    });
    console.log("test");
    expect(messages).toEqual(["hello from client"]);
    done();
  });
});
bun test v1.1.4 (fbe2fe0c)

test/index.test.ts:
error: Test "Websocket with instance" timed out after 5000ms
✗ Websocket with instance [5001.24ms]

 0 pass
 1 fail
Ran 1 tests across 1 files. [5.07s]
kidqueb commented 4 months ago

https://github.com/elysiajs/eden/blob/main/src/treaty2/index.ts#L458

http://e.ly should probably be something like app.server.url.origin

Too lazy to fix my pending PR to not be on main of my fork right now so I leave it you all