import { jest } from "@jest/globals"; // Manual DB mock — assert the SQL/params the query builder produces without a DB. const query = jest.fn(); const release = jest.fn(async () => {}); jest.unstable_mockModule("../../db/index.js", () => ({ getPool: async () => ({ query, release }) })); const { listCore, listAudit } = await import("./transactions.js"); // listCore/listAudit each run a COUNT then a rows query. function prime(total = 0, rows = []) { query.mockResolvedValueOnce({ rows: [{ total }] }).mockResolvedValueOnce({ rows }); } beforeEach(() => { query.mockReset(); release.mockClear(); }); describe("listCore search guard", () => { it("omits the ILIKE search predicate (and the q param) when there is no query term", async () => { prime(0, []); await listCore(7, { from: "2026-01-01", to: "2026-01-31" }); const [countSql, countParams] = query.mock.calls[0]; expect(countSql).not.toMatch(/ILIKE/); expect(countParams).toEqual([7, "2026-01-01", "2026-01-31"]); // no q appended }); it("adds the ILIKE search predicate + q param only when a query term is present", async () => { prime(1, [{ eventUuid: "e1" }]); await listCore(7, { from: "2026-01-01", to: "2026-01-31", q: "acme" }); const [countSql, countParams] = query.mock.calls[0]; expect(countSql).toMatch(/ILIKE/); expect(countParams).toEqual([7, "2026-01-01", "2026-01-31", "acme"]); }); it("resolves sender/receiver to entity short names via COALESCE + LEFT JOIN entity", async () => { prime(1, [{ eventUuid: "e1", sender: "acme", receiver: "did:x" }]); const out = await listCore(7, {}); const rowsSql = query.mock.calls[1][0]; expect(rowsSql).toMatch(/COALESCE\(es\.short_name, e\.sender_id\)/); expect(rowsSql).toMatch(/COALESCE\(er\.short_name, e\.recipient_id\)/); expect(rowsSql).toMatch(/LEFT JOIN entity/); expect(out).toEqual({ rows: [{ eventUuid: "e1", sender: "acme", receiver: "did:x" }], total: 1 }); }); }); describe("listAudit", () => { it("omits the ILIKE search predicate by default", async () => { prime(0, []); await listAudit(7, { from: "2026-01-01", to: "2026-01-31" }); expect(query.mock.calls[0][0]).not.toMatch(/ILIKE/); }); it("keeps the display-only entity joins OUT of the COUNT query but IN the rows query", async () => { prime(2, [{ eventUuid: "e1" }]); await listAudit(7, { q: "x" }); const countSql = query.mock.calls[0][0]; const rowsSql = query.mock.calls[1][0]; expect(countSql).not.toMatch(/LEFT JOIN entity/); expect(rowsSql).toMatch(/LEFT JOIN entity/); }); });