import { createServer } from "http"; import { describe, it, expect, beforeEach, afterEach } from "bun:test"; import { io as ioc, Socket as ClientSocket } from "socket.io-client"; import { Adapter, BroadcastOptions } from "socket.io-adapter"; import type { AddressInfo } from "net"; import { Server } from "socket.io"; import { createPartialDone } from "./support/util.ts"; const SOCKETS_COUNT = 3; class DummyAdapter extends Adapter { fetchSockets(opts: BroadcastOptions): Promise { return Promise.resolve([ { id: "42", handshake: { headers: { accept: "*/*", }, query: { transport: "polling", EIO: "4", }, }, rooms: ["42", "room1"], data: { username: "john", }, }, ]); } } // Hanging tests are disabled because they cause the test suite to hang describe.skip("utility methods", () => { let io: Server, clientSockets: ClientSocket[], serverSockets: Socket[]; beforeEach(done => { const srv = createServer(); io = new Server(srv); const timeout = setTimeout(() => { serverSockets = []; // done(new Error("timeout")); done(); }, 300); srv.listen(() => { const port = (srv.address() as AddressInfo).port; clientSockets = []; for (let i = 0; i < SOCKETS_COUNT; i++) { clientSockets.push( ioc(`http://localhost:${port}`, { // FIXME needed so that clients are properly closed transports: ["websocket"], }), ); } serverSockets = []; io.on("connection", (socket: Socket) => { serverSockets.push(socket); if (serverSockets.length === SOCKETS_COUNT) { clearTimeout(timeout); done(); } }); }); }); afterEach(() => { io.close(); clientSockets.forEach(socket => socket.disconnect()); }); describe("fetchSockets", () => { it.skip("returns all socket instances", async () => { const sockets = await io.fetchSockets(); expect(sockets.length).toBe(3); }); it.skip("returns all socket instances in the given room", async () => { serverSockets[0]?.join(["room1", "room2"]); serverSockets[1]?.join("room1"); serverSockets[2]?.join("room2"); const sockets = await io.in("room1").fetchSockets(); expect(sockets.length).toBe(2); }); it.skip("works with a custom adapter", async () => { io.adapter(DummyAdapter); const sockets = await io.fetchSockets(); expect(sockets.length).toBe(1); const remoteSocket = sockets[0]; expect(remoteSocket.id).toBe("42"); expect(remoteSocket.rooms).toStrictEqual(new Set(["42", "room1"])); expect(remoteSocket.data).toStrictEqual({ username: "john" }); }); }); describe("socketsJoin", () => { it("makes all socket instances join the given room", () => { io.socketsJoin("room1"); serverSockets.forEach(socket => { expect(socket.rooms).toContain("room1"); }); }); it.skip("makes all socket instances in a room join the given room", () => { serverSockets[0]?.join(["room1", "room2"]); serverSockets[1]?.join("room1"); serverSockets[2]?.join("room2"); io.in("room1").socketsJoin("room3"); expect(serverSockets[0]?.rooms).toContain("room3"); expect(serverSockets[1]?.rooms).toContain("room3"); expect(serverSockets[2]?.rooms).not.toContain("room3"); }); }); describe("socketsLeave", () => { it.skip("makes all socket instances leave the given room", () => { serverSockets[0]?.join(["room1", "room2"]); serverSockets[1]?.join("room1"); serverSockets[2]?.join("room2"); io.socketsLeave("room1"); expect(serverSockets[0]?.rooms).toContain("room2"); expect(serverSockets[0]?.rooms).toContain("room1"); expect(serverSockets[1]?.rooms).not.toContain("room1"); }); it.skip("makes all socket instances in a room leave the given room", () => { serverSockets[0]?.join(["room1", "room2"]); serverSockets[1]?.join("room1"); serverSockets[2]?.join("room2"); io.in("room2").socketsLeave("room1"); expect(serverSockets[0]?.rooms).toContain("room2"); expect(serverSockets[0]?.rooms).not.toContain("room1"); expect(serverSockets[1]?.rooms).toContain("room1"); }); }); describe("disconnectSockets", () => { it.skip("makes all socket instances disconnect", done => { io.disconnectSockets(true); const timeout = setTimeout(() => { done(new Error("timeout")); }, 300); const partialDone = createPartialDone(3, err => { clearTimeout(timeout); done(err); }); clientSockets[0].on("disconnect", partialDone); clientSockets[1].on("disconnect", partialDone); clientSockets[2].on("disconnect", partialDone); }); it.skip("makes all socket instances in a room disconnect", done => { const timeout = setTimeout(() => { done(new Error("timeout")); }, 300); serverSockets[0]?.join(["room1", "room2"]); serverSockets[1]?.join("aroom1"); serverSockets[2]?.join("room2"); io.in("room2").disconnectSockets(true); const partialDone = createPartialDone(2, err => { clearTimeout(timeout); clientSockets[1].off("disconnect"); done(err); }); clientSockets[0].on("disconnect", partialDone); clientSockets[1].on("disconnect", () => { done(new Error("should not happen")); }); clientSockets[2].on("disconnect", partialDone); }); }); });