Files
optima/tests/integration/errorHandling.test.ts
T

112 lines
3.5 KiB
TypeScript

import { describe, test, expect } from "bun:test";
import { Hono } from "hono";
import { apiResponse } from "../../src/modules/api-utils/apiResponse";
import { ZodError } from "zod";
import GenericError from "../../src/Errors/GenericError";
/**
* Tests the error-handling middleware registered in server.ts.
* We replicate the onError logic on a fresh Hono instance to test
* in isolation without importing all routes.
*/
function createAppWithErrorHandling() {
const app = new Hono();
app.onError((err, ctx) => {
const errClassName = err.constructor.name;
if (
errClassName.toLowerCase().includes("prisma") ||
err.message.toLowerCase().includes("prisma") ||
err.name.toLowerCase().includes("prisma")
) {
return ctx.json(apiResponse.internalError(), 500);
}
if (err instanceof ZodError || err.name === "ZodError") {
const zodResp = apiResponse.zodError(err as ZodError);
return ctx.json(zodResp, zodResp.status as any);
}
const response = apiResponse.error(err);
return ctx.json(response, response.status);
});
return app;
}
describe("Server error handling", () => {
test("Prisma errors return 500 InternalServerError", async () => {
const app = createAppWithErrorHandling();
app.get("/test", () => {
const err = new Error("prisma query failed");
throw err;
});
const res = await app.request("/test");
expect(res.status).toBe(500);
const body: any = await res.json();
expect(body.error).toBe("InternalServerError");
expect(body.successful).toBe(false);
});
test("Prisma errors detected by class name", async () => {
const app = createAppWithErrorHandling();
app.get("/test", () => {
class PrismaClientError extends Error {
constructor() {
super("something");
this.name = "PrismaClientError";
}
}
throw new PrismaClientError();
});
const res = await app.request("/test");
expect(res.status).toBe(500);
});
test("ZodError returns 400 with error array", async () => {
const app = createAppWithErrorHandling();
app.get("/test", (c) => {
// In Zod v4, we need to use z.parse to generate a proper ZodError
const { z } = require("zod");
const schema = z.object({ name: z.string() });
schema.parse({}); // throws ZodError
return c.text("unreachable");
});
const res = await app.request("/test");
expect(res.status).toBe(400);
const body: any = await res.json();
expect(body.message).toBe("TypeError");
expect(body.successful).toBe(false);
expect(Array.isArray(body.error)).toBe(true);
});
test("GenericError returns custom status", async () => {
const app = createAppWithErrorHandling();
app.get("/test", () => {
throw new GenericError({
name: "NotFound",
message: "Resource not found",
status: 404,
});
});
const res = await app.request("/test");
expect(res.status).toBe(404);
const body: any = await res.json();
expect(body.error).toBe("NotFound");
expect(body.message).toBe("Resource not found");
expect(body.successful).toBe(false);
});
test("plain Error defaults to 400", async () => {
const app = createAppWithErrorHandling();
app.get("/test", () => {
throw new Error("Unexpected error");
});
const res = await app.request("/test");
expect(res.status).toBe(400);
const body: any = await res.json();
expect(body.successful).toBe(false);
});
});