import { describe, test, expect, mock, beforeEach } from "bun:test"; const SocketIOAdapter = require("./socketio-adapter.js"); // EventEmitter minimal pour simuler un socket.io function createFakeSocket() { const listeners = {}; const socket = { on(event, fn) { (listeners[event] ??= []).push(fn); }, once(event, fn) { const wrapper = (...args) => { socket.off(event, wrapper); fn(...args); }; (listeners[event] ??= []).push(wrapper); }, off(event, fn) { if (fn) { listeners[event] = (listeners[event] || []).filter(f => f !== fn); } else { delete listeners[event]; } }, emit: mock(() => {}), disconnect: mock(() => {}), connected: true, // Helper test : déclencher un event côté "serveur" _fire(event, ...args) { (listeners[event] || []).slice().forEach(fn => fn(...args)); }, }; return socket; } describe("SocketIOAdapter", () => { let adapter, socket; beforeEach(() => { socket = null; const factory = (url, opts) => { socket = createFakeSocket(); return socket; }; adapter = new SocketIOAdapter("http://localhost:8004", factory); }); test("état initial = disconnected", () => { expect(adapter.state).toBe("disconnected"); }); test("connect() passe en connecting puis connected sur login_ok", async () => { const states = []; adapter.onStateChange((s) => states.push(s)); const p = adapter.connect("1234", "pass", "2001"); socket._fire("login_ok", { accessCode: "1234", firstName: "Test", lastName: "User", connList: [] }); const result = await p; expect(states).toEqual(["connecting", "connected"]); expect(adapter.state).toBe("connected"); expect(result.accessCode).toBe("1234"); }); test("connect() rejette sur login_error", async () => { const p = adapter.connect("1234", "wrong", "2001"); socket._fire("login_error", { message: "Mot de passe incorrect" }); expect(p).rejects.toThrow("Mot de passe incorrect"); expect(adapter.state).toBe("error"); }); test("connect() rejette sur connect_error", async () => { const p = adapter.connect("1234", "pass", "2001"); socket._fire("connect_error", new Error("Connection refused")); expect(p).rejects.toThrow("Connection refused"); expect(adapter.state).toBe("error"); }); test("déconnexion temporaire passe en reconnecting", async () => { const p = adapter.connect("1234", "pass", "2001"); socket._fire("login_ok", { accessCode: "1234" }); await p; socket._fire("disconnect", "transport close"); expect(adapter.state).toBe("reconnecting"); }); test("reconnexion après déconnexion repasse en connected", async () => { const p = adapter.connect("1234", "pass", "2001"); socket._fire("login_ok", { accessCode: "1234" }); await p; socket._fire("disconnect", "transport close"); expect(adapter.state).toBe("reconnecting"); socket._fire("login_ok", { accessCode: "1234" }); expect(adapter.state).toBe("connected"); }); test("logoff() émet logout et passe en disconnected sur logout_ok", async () => { const p = adapter.connect("1234", "pass", "2001"); socket._fire("login_ok", { accessCode: "1234" }); await p; const logoffP = adapter.logoff(); socket._fire("logout_ok"); await logoffP; expect(socket.emit).toHaveBeenCalledWith("logout"); expect(adapter.state).toBe("disconnected"); }); test("onStateChange est appelé à chaque transition", async () => { const states = []; adapter.onStateChange((s) => states.push(s)); const p = adapter.connect("1234", "pass", "2001"); socket._fire("login_ok", { accessCode: "1234" }); await p; socket._fire("disconnect", "transport close"); socket._fire("login_ok", { accessCode: "1234" }); expect(states).toEqual(["connecting", "connected", "reconnecting", "connected"]); }); });