From 6137d11e5fbab342e482300d0694b60347bc217a Mon Sep 17 00:00:00 2001 From: Hardik Date: Sun, 21 Jun 2026 02:05:32 +0530 Subject: [PATCH] test(companies): cover createCompany/updateCompany actions Satisfies the contribution-policy test gate for the add/edit-page refactor. Covers: createCompany returns the new id, code upper-casing, duplicate-code rejection, updateCompany in-place edit, and manage_vessels_accounts gating. Co-Authored-By: Claude Opus 4.8 --- App/tests/integration/company-crud.test.ts | 84 ++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 App/tests/integration/company-crud.test.ts diff --git a/App/tests/integration/company-crud.test.ts b/App/tests/integration/company-crud.test.ts new file mode 100644 index 0000000..423e983 --- /dev/null +++ b/App/tests/integration/company-crud.test.ts @@ -0,0 +1,84 @@ +/** + * Integration tests for company create/update actions. + * Focus on the behaviour the dedicated add/edit pages rely on: + * - createCompany returns the new id (so the create flow can redirect to the edit page) + * - fields persist, code is upper-cased, duplicate codes are rejected + * - updateCompany edits in place + * - both actions are gated by manage_vessels_accounts + */ +import { vi, describe, it, expect, afterAll } from "vitest"; + +vi.mock("@/auth", () => ({ auth: vi.fn() })); +vi.mock("next/cache", () => ({ revalidatePath: vi.fn() })); + +import { auth } from "@/auth"; +import { db } from "@/lib/db"; +import { createCompany, updateCompany } from "@/app/(portal)/admin/companies/actions"; +import { makeSession, fd } from "./helpers"; + +const mockedAuth = vi.mocked(auth); +const NAME_PREFIX = "INTTEST_CRUD_"; + +afterAll(async () => { + await db.company.deleteMany({ where: { name: { startsWith: NAME_PREFIX } } }); +}); + +describe("createCompany", () => { + it("returns the new id and persists the company (code upper-cased)", async () => { + mockedAuth.mockResolvedValue(makeSession("u-mgr", "MANAGER") as never); + const result = await createCompany(fd({ + name: `${NAME_PREFIX}Alpha`, + code: "zzcrudA", + gstNumber: "27AAHCP5787B1Z6", + })); + + expect("id" in result && result.ok).toBe(true); + if (!("id" in result)) throw new Error(result.error); + + const c = await db.company.findUniqueOrThrow({ where: { id: result.id } }); + expect(c.name).toBe(`${NAME_PREFIX}Alpha`); + expect(c.code).toBe("ZZCRUDA"); + expect(c.gstNumber).toBe("27AAHCP5787B1Z6"); + }); + + it("rejects a duplicate code (case-insensitive)", async () => { + mockedAuth.mockResolvedValue(makeSession("u-mgr", "MANAGER") as never); + const first = await createCompany(fd({ name: `${NAME_PREFIX}Dup1`, code: "zzcrudd" })); + expect("id" in first).toBe(true); + + const second = await createCompany(fd({ name: `${NAME_PREFIX}Dup2`, code: "ZZCRUDD" })); + expect("error" in second).toBe(true); + }); + + it("refuses callers without manage_vessels_accounts", async () => { + mockedAuth.mockResolvedValue(makeSession("u-tech", "TECHNICAL") as never); + const result = await createCompany(fd({ name: `${NAME_PREFIX}Nope`, code: "zzcrudN" })); + expect(result).toEqual({ error: "Unauthorized" }); + }); +}); + +describe("updateCompany", () => { + it("edits an existing company in place", async () => { + mockedAuth.mockResolvedValue(makeSession("u-mgr", "MANAGER") as never); + const created = await createCompany(fd({ name: `${NAME_PREFIX}Edit`, code: "zzcrudE" })); + if (!("id" in created)) throw new Error(created.error); + + const result = await updateCompany(fd({ + id: created.id, + name: `${NAME_PREFIX}Edited`, + code: "zzcrudE", + mobile: "+91 99999 00000", + })); + expect(result).toEqual({ ok: true }); + + const c = await db.company.findUniqueOrThrow({ where: { id: created.id } }); + expect(c.name).toBe(`${NAME_PREFIX}Edited`); + expect(c.mobile).toBe("+91 99999 00000"); + }); + + it("refuses callers without manage_vessels_accounts", async () => { + mockedAuth.mockResolvedValue(makeSession("u-tech", "TECHNICAL") as never); + const result = await updateCompany(fd({ id: "whatever", name: "x", code: "ZZX" })); + expect(result).toEqual({ error: "Unauthorized" }); + }); +});