import { TRPCError } from "@trpc/server"; import { describe, expect, it, vi } from "vitest"; import { assertClientCodeAvailable, assertClientDeletable, buildClientCreateData, buildClientListWhere, buildClientTree, buildClientUpdateData, findClientByIdentifier, } from "../router/client-support.js"; describe("client support", () => { it("builds client list filters", () => { expect(buildClientListWhere({ parentId: "parent_1", isActive: true, search: "Acme", })).toEqual({ parentId: "parent_1", isActive: true, OR: [ { name: { contains: "Acme", mode: "insensitive" } }, { code: { contains: "Acme", mode: "insensitive" } }, ], }); }); it("builds a sorted nested client tree", () => { expect(buildClientTree([ { id: "client_child_b", name: "Beta", code: "BET", parentId: "client_root", isActive: true, sortOrder: 20, tags: [], createdAt: new Date("2026-03-01T00:00:00.000Z"), updatedAt: new Date("2026-03-01T00:00:00.000Z"), }, { id: "client_root", name: "Root", code: "ROOT", parentId: null, isActive: true, sortOrder: 10, tags: [], createdAt: new Date("2026-03-01T00:00:00.000Z"), updatedAt: new Date("2026-03-01T00:00:00.000Z"), }, { id: "client_child_a", name: "Alpha", code: "ALP", parentId: "client_root", isActive: true, sortOrder: 20, tags: [], createdAt: new Date("2026-03-01T00:00:00.000Z"), updatedAt: new Date("2026-03-01T00:00:00.000Z"), }, ])).toEqual([ expect.objectContaining({ id: "client_root", children: [ expect.objectContaining({ id: "client_child_a", children: [] }), expect.objectContaining({ id: "client_child_b", children: [] }), ], }), ]); }); it("resolves a client by code before fuzzy fallback", async () => { const db = { client: { findUnique: vi.fn() .mockResolvedValueOnce(null) .mockResolvedValueOnce({ id: "client_1", code: "ACME" }), findFirst: vi.fn(), }, } as never; const result = await findClientByIdentifier<{ id: string; code: string }>( db, " ACME ", { select: { id: true, code: true } }, ); expect(result).toEqual({ id: "client_1", code: "ACME" }); expect(db.client.findUnique).toHaveBeenNthCalledWith(2, { where: { code: "ACME" }, select: { id: true, code: true }, }); }); it("throws when no client matches the identifier", async () => { const db = { client: { findUnique: vi.fn().mockResolvedValue(null), findFirst: vi.fn().mockResolvedValue(null), }, } as never; await expect(findClientByIdentifier(db, "missing", { select: { id: true } })).rejects.toBeInstanceOf(TRPCError); }); it("builds create and sparse update payloads", () => { expect(buildClientCreateData({ name: "Acme", code: "ACME", parentId: "parent_1", sortOrder: 10, tags: ["enterprise"], })).toEqual({ name: "Acme", code: "ACME", parentId: "parent_1", sortOrder: 10, tags: ["enterprise"], }); expect(buildClientUpdateData({ code: null, isActive: false, parentId: null, })).toEqual({ code: null, isActive: false, parentId: null, }); }); it("rejects duplicate client codes outside the ignored id", async () => { const db = { client: { findUnique: vi.fn().mockResolvedValue({ id: "client_existing", code: "ACME" }), }, } as never; await expect(assertClientCodeAvailable(db, "ACME")).rejects.toMatchObject({ code: "CONFLICT", message: 'Client code "ACME" already exists', }); }); it("rejects deletion when projects or children still exist", () => { expect(() => assertClientDeletable({ _count: { projects: 2, children: 0 }, })).toThrow(TRPCError); expect(() => assertClientDeletable({ _count: { projects: 0, children: 1 }, })).toThrow(TRPCError); }); });