f7407bd882
P2002/P2025/P2003 now map to CONFLICT/NOT_FOUND/BAD_REQUEST with generic messages. Raw Prisma error details no longer reach the client. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
73 lines
2.8 KiB
TypeScript
73 lines
2.8 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import { Prisma } from "@capakraken/db";
|
|
import { TRPCError } from "@trpc/server";
|
|
|
|
// We need to stub out the prisma client import used by trpc.ts before importing
|
|
vi.mock("@capakraken/db", async (importOriginal) => {
|
|
const original = await importOriginal<typeof import("@capakraken/db")>();
|
|
return {
|
|
...original,
|
|
prisma: {
|
|
systemRoleConfig: { findMany: vi.fn(async () => []) },
|
|
},
|
|
};
|
|
});
|
|
|
|
// eslint-disable-next-line import/first
|
|
import { mapPrismaError } from "../trpc.js";
|
|
|
|
function makePrismaError(code: string): Prisma.PrismaClientKnownRequestError {
|
|
return new Prisma.PrismaClientKnownRequestError("test message", {
|
|
code,
|
|
clientVersion: "test",
|
|
});
|
|
}
|
|
|
|
describe("mapPrismaError", () => {
|
|
it("maps P2002 (unique constraint) to CONFLICT", () => {
|
|
const err = makePrismaError("P2002");
|
|
const result = mapPrismaError(err);
|
|
expect(result).toBeInstanceOf(TRPCError);
|
|
expect(result.code).toBe("CONFLICT");
|
|
expect(result.message).toBe("A record with this value already exists.");
|
|
});
|
|
|
|
it("maps P2025 (record not found) to NOT_FOUND", () => {
|
|
const err = makePrismaError("P2025");
|
|
const result = mapPrismaError(err);
|
|
expect(result).toBeInstanceOf(TRPCError);
|
|
expect(result.code).toBe("NOT_FOUND");
|
|
expect(result.message).toBe("The requested record was not found.");
|
|
});
|
|
|
|
it("maps P2003 (foreign key constraint) to BAD_REQUEST", () => {
|
|
const err = makePrismaError("P2003");
|
|
const result = mapPrismaError(err);
|
|
expect(result).toBeInstanceOf(TRPCError);
|
|
expect(result.code).toBe("BAD_REQUEST");
|
|
expect(result.message).toBe("A referenced record does not exist.");
|
|
});
|
|
|
|
it("maps an unknown Prisma code (P9999) to INTERNAL_SERVER_ERROR", () => {
|
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
const err = makePrismaError("P9999");
|
|
const result = mapPrismaError(err);
|
|
expect(result).toBeInstanceOf(TRPCError);
|
|
expect(result.code).toBe("INTERNAL_SERVER_ERROR");
|
|
expect(result.message).toBe("A database error occurred.");
|
|
expect(consoleSpy).toHaveBeenCalledWith("[Prisma error]", "P9999", "test message");
|
|
consoleSpy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe("withPrismaErrors middleware (integration)", () => {
|
|
it("passes through non-Prisma errors unchanged", async () => {
|
|
// We test this by verifying mapPrismaError is only invoked for Prisma errors.
|
|
// A plain Error should not be caught by mapPrismaError.
|
|
const plain = new Error("network failure");
|
|
// mapPrismaError only accepts PrismaClientKnownRequestError, so passing a plain
|
|
// Error through the middleware would re-throw it. We verify the type guard here:
|
|
expect(plain instanceof Prisma.PrismaClientKnownRequestError).toBe(false);
|
|
});
|
|
});
|