import { jest } from "@jest/globals"; // Manual DB mock: getPool() returns a fake client whose query() the test drives. const query = jest.fn(); const release = jest.fn(async () => {}); jest.unstable_mockModule("../../db/index.js", () => ({ getPool: async () => ({ query, release }) })); const { getCached } = await import("./cache.js"); beforeEach(() => { query.mockReset(); release.mockClear(); }); describe("getCached", () => { it("returns the cached value on a fresh hit without computing", async () => { query.mockResolvedValueOnce({ rows: [{ data: { v: 1 } }] }); const compute = jest.fn(async () => ({ v: 999 })); const out = await getCached(7, "storage", 1000, compute); expect(out).toEqual({ v: 1 }); expect(compute).not.toHaveBeenCalled(); expect(query).toHaveBeenCalledTimes(1); // SELECT only expect(query.mock.calls[0][1]).toEqual([7, "storage", 1000]); }); it("computes and upserts on a miss", async () => { query.mockResolvedValueOnce({ rows: [] }).mockResolvedValueOnce({ rows: [] }); // SELECT miss, then INSERT const compute = jest.fn(async () => ({ v: 2 })); const out = await getCached(7, "storage", 1000, compute); expect(out).toEqual({ v: 2 }); expect(compute).toHaveBeenCalledTimes(1); expect(query).toHaveBeenCalledTimes(2); // SELECT then INSERT const [sql, params] = query.mock.calls[1]; expect(sql).toContain("ON CONFLICT (user_id, tag) DO UPDATE"); expect(params).toEqual([7, "storage", { v: 2 }]); }); it("does not cache when compute throws", async () => { query.mockResolvedValueOnce({ rows: [] }); const compute = jest.fn(async () => { throw new Error("nope"); }); await expect(getCached(7, "storage", 1000, compute)).rejects.toThrow("nope"); expect(query).toHaveBeenCalledTimes(1); // SELECT only; no INSERT }); });