import { describe, it, expect, afterAll } from "vitest"; import prisma from "../config/database"; import { listPlanCategories, createPlanCategory, updatePlanCategory, deactivatePlanCategory, deletePlanCategory, isCategoryKeyActive, slugifyCategory, } from "../services/planCategory.service"; const created: number[] = []; afterAll(async () => { if (created.length) { await prisma.plan_categories.deleteMany({ where: { id: { in: created } } }); } await prisma.$disconnect(); }); describe("slugifyCategory", () => { it("strips Czech diacritics and non-alphanumerics", () => { expect(slugifyCategory("Cesta / Montáž")).toBe("cesta_montaz"); expect(slugifyCategory("Příprava")).toBe("priprava"); }); }); describe("plan category service", () => { it("seeds are present and ordered", async () => { const cats = await listPlanCategories(true); const keys = cats.map((c) => c.key); expect(keys).toContain("work"); expect(keys).toContain("other"); }); it("creates a category with a unique slug and next sort_order", async () => { const res = await createPlanCategory({ label: "Test Kategorie ZZ", color: "#123456", }); if ("error" in res) throw new Error(res.error); created.push(res.data.id); expect(res.data.key).toBe("test_kategorie_zz"); expect(res.data.color).toBe("#123456"); expect(res.data.is_active).toBe(true); expect(await isCategoryKeyActive("test_kategorie_zz")).toBe(true); }); it("dedupes a colliding slug", async () => { const res = await createPlanCategory({ label: "Test Kategorie ZZ", color: "#222222", }); if ("error" in res) throw new Error(res.error); created.push(res.data.id); expect(res.data.key).toBe("test_kategorie_zz_2"); }); it("updates label and color (key immutable)", async () => { const res = await createPlanCategory({ label: "Test Upd ZZ", color: "#aaaaaa", }); if ("error" in res) throw new Error(res.error); created.push(res.data.id); const upd = await updatePlanCategory(res.data.id, { label: "Test Upd2 ZZ", color: "#bbbbbb", }); if ("error" in upd) throw new Error(upd.error); expect(upd.data.label).toBe("Test Upd2 ZZ"); expect(upd.data.color).toBe("#bbbbbb"); expect(upd.data.key).toBe("test_upd_zz"); }); it("deactivate hides the key from active check", async () => { const res = await createPlanCategory({ label: "Test Deact ZZ", color: "#cccccc", }); if ("error" in res) throw new Error(res.error); created.push(res.data.id); await deactivatePlanCategory(res.data.id); expect(await isCategoryKeyActive("test_deact_zz")).toBe(false); }); it("hard-deletes an unused category", async () => { const res = await createPlanCategory({ label: "Test Del ZZ", color: "#dddddd", }); if ("error" in res) throw new Error(res.error); const del = await deletePlanCategory(res.data.id); expect("data" in del).toBe(true); const stillThere = await prisma.plan_categories.findUnique({ where: { id: res.data.id }, }); expect(stillThere).toBeNull(); }); it("refuses to hard-delete a category in use", async () => { const res = await createPlanCategory({ label: "Test InUse ZZ", color: "#eeeeee", }); if ("error" in res) throw new Error(res.error); created.push(res.data.id); const user = await prisma.users.findFirst({ select: { id: true } }); if (!user) throw new Error("no user in test DB"); const entry = await prisma.work_plan_entries.create({ data: { user_id: user.id, date_from: new Date("2026-06-10T00:00:00.000Z"), date_to: new Date("2026-06-10T00:00:00.000Z"), category: res.data.key, note: "test in-use", created_by: user.id, }, }); try { const del = await deletePlanCategory(res.data.id); expect("error" in del).toBe(true); if ("error" in del) expect(del.status).toBe(409); } finally { await prisma.work_plan_entries.delete({ where: { id: entry.id } }); } }); });