import {render, screen, act} from "@testing-library/react"; import "@testing-library/jest-dom"; import {type Cell, cell, useCell} from "../../src/utils/cellStore.ts"; describe("cell store (unit)", () => { it("returns initial value with get()", () => { const c = cell(123); expect(c.get()).toBe(123); }); it("updates value with set(next)", () => { const c = cell("a"); c.set("b"); expect(c.get()).toBe("b"); }); it("gives previous value in set(updater)", () => { const c = cell(1); c.set((prev) => prev + 2); expect(c.get()).toBe(3); }); it("calls subscribe callback on set", () => { const c = cell(0); const cb = jest.fn(); const unsub = c.subscribe(cb); c.set(1); c.set(2); expect(cb).toHaveBeenCalledTimes(2); unsub(); }); it("stops notifications when unsubscribing", () => { const c = cell(0); const cb = jest.fn(); const unsub = c.subscribe(cb); c.set(1); unsub(); c.set(2); expect(cb).toHaveBeenCalledTimes(1); }); it("updates multiple listeners", () => { const c = cell("x"); const a = jest.fn(); const b = jest.fn(); const ua = c.subscribe(a); const ub = c.subscribe(b); c.set("y"); expect(a).toHaveBeenCalledTimes(1); expect(b).toHaveBeenCalledTimes(1); ua(); ub(); }); }); describe("cell store (integration)", () => { function View({c, label}: { c: Cell; label: string }) { const v = useCell(c); // count renders to verify re-render behavior (View as any).__renders = ((View as any).__renders ?? 0) + 1; return
{String(v)}
; } it("reads initial value and updates on set", () => { const c = cell("hello"); render(); expect(screen.getByTestId("value")).toHaveTextContent("hello"); act(() => { c.set("world"); }); expect(screen.getByTestId("value")).toHaveTextContent("world"); }); it("triggers one re-render with set", () => { const c = cell(1); (View as any).__renders = 0; render(); const rendersAfterMount = (View as any).__renders; act(() => { c.set((prev: number) => prev + 1); }); // exactly one extra render from the update expect((View as any).__renders).toBe(rendersAfterMount + 1); expect(screen.getByTestId("num")).toHaveTextContent("2"); }); it("unsubscribes on unmount (no errors on later sets)", () => { const c = cell("a"); const {unmount} = render(); unmount(); // should not throw even though there was a subscriber expect(() => act(() => { c.set("b"); }) ).not.toThrow(); }); it("only re-renders components that use the cell", () => { const a = cell("A"); const b = cell("B"); let rendersA = 0; let rendersB = 0; function A() { const v = useCell(a); rendersA++; return
{v}
; } function B() { const v = useCell(b); rendersB++; return
{v}
; } render( <> ); const rendersAAfterMount = rendersA; const rendersBAfterMount = rendersB; act(() => { a.set("A2"); // only A should update }); expect(screen.getByTestId("A")).toHaveTextContent("A2"); expect(screen.getByTestId("B")).toHaveTextContent("B"); expect(rendersA).toBe(rendersAAfterMount + 1); expect(rendersB).toBe(rendersBAfterMount); // unchanged }); });