import { renderHook } from "@testing-library/react"; import { act } from "react"; import { FakeEventSource } from "../test/fakeEventSource"; import { useSessionStream } from "./useSessionStream"; import { useSessionStore } from "../store/sessionStore"; beforeEach(() => { FakeEventSource.instances = []; (globalThis as any).EventSource = FakeEventSource; useSessionStore.getState().resetSession(); }); test("opens an EventSource and feeds NAMED events to the store", () => { renderHook(() => useSessionStream("s1")); const es = FakeEventSource.instances[0]; expect(es.url).toBe("http://localhost:8787/sessions/s1/events"); // Backend sends `event: ui_request` (named) — drive the addEventListener path // that production relies on, not the unnamed onmessage fallback. act(() => es.emitNamed("ui_request", { type: "ui_request", ui_request: { id: "u1", widget: "select" } }) ); expect(useSessionStore.getState().pendingWidget?.id).toBe("u1"); }); test("feeds named activity_delta events to the model activity store", () => { renderHook(() => useSessionStream("s1")); const es = FakeEventSource.instances[0]; act(() => es.emitNamed("activity_delta", { type: "activity_delta", text: "Analizzo le ambiguità" }) ); expect(useSessionStore.getState().activity.at(-1)?.text).toBe("Analizzo le ambiguità"); }); test("also feeds UNNAMED (default message) events to the store", () => { renderHook(() => useSessionStream("s1")); const es = FakeEventSource.instances[0]; act(() => es.emit({ type: "text_delta", text: "hello" })); expect(useSessionStore.getState().transcript.at(-1)?.text).toBe("hello"); }); test("closes the stream on unmount", () => { const { unmount } = renderHook(() => useSessionStream("s1")); const es = FakeEventSource.instances[0]; unmount(); expect(es.closed).toBe(true); }); test("reconnects the same session when the generation changes", () => { const { rerender } = renderHook( ({ generation }) => useSessionStream("s1", generation), { initialProps: { generation: 0 } }, ); const first = FakeEventSource.instances[0]; rerender({ generation: 1 }); expect(first.closed).toBe(true); expect(FakeEventSource.instances).toHaveLength(2); expect(FakeEventSource.instances[1].url).toBe(first.url); });