import { describe, test, expect, beforeEach } from "bun:test"; import { apiResponse } from "../../src/modules/api-utils/apiResponse"; import { z } from "zod"; import GenericError from "../../src/Errors/GenericError"; describe("apiResponse", () => { // ------------------------------------------------------------------- // successful // ------------------------------------------------------------------- describe("successful()", () => { test("returns status 200 and successful: true", () => { const res = apiResponse.successful("OK"); expect(res.status).toBe(200); expect(res.successful).toBe(true); expect(res.message).toBe("OK"); }); test("includes data when provided", () => { const data = { id: 1, name: "Test" }; const res = apiResponse.successful("OK", data); expect(res.data).toEqual(data); }); test("data is undefined when not provided", () => { const res = apiResponse.successful("OK"); expect(res.data).toBeUndefined(); }); test("includes meta.timestamp", () => { const before = Date.now(); const res = apiResponse.successful("OK"); const after = Date.now(); expect(res.meta.timestamp).toBeGreaterThanOrEqual(before); expect(res.meta.timestamp).toBeLessThanOrEqual(after); }); test("accepts optional meta parameter (overridden by timestamp)", () => { const res = apiResponse.successful("OK", null, { custom: true } as any); // The implementation replaces meta entirely with { timestamp } expect(res.meta.timestamp).toBeDefined(); }); }); // ------------------------------------------------------------------- // created // ------------------------------------------------------------------- describe("created()", () => { test("returns status 201 and successful: true", () => { const res = apiResponse.created("Created"); expect(res.status).toBe(201); expect(res.successful).toBe(true); expect(res.message).toBe("Created"); }); test("includes data when provided", () => { const res = apiResponse.created("Created", { id: "abc" }); expect(res.data).toEqual({ id: "abc" }); }); test("data is undefined when not provided", () => { const res = apiResponse.created("Created"); expect(res.data).toBeUndefined(); }); test("includes meta.timestamp", () => { const res = apiResponse.created("Created"); expect(res.meta.timestamp).toBeDefined(); expect(typeof res.meta.timestamp).toBe("number"); }); }); // ------------------------------------------------------------------- // error // ------------------------------------------------------------------- describe("error()", () => { test("reads status from error object", () => { const err = new GenericError({ name: "Oops", message: "bad", status: 422, }); const res = apiResponse.error(err); expect(res.status).toBe(422); expect(res.message).toBe("bad"); expect(res.error).toBe("Oops"); expect(res.successful).toBe(false); }); test("defaults status to 400 when error has no status", () => { const err = new Error("plain error"); const res = apiResponse.error(err); expect(res.status).toBe(400); }); test("includes meta.timestamp", () => { const err = new Error("x"); const res = apiResponse.error(err); expect(res.meta.timestamp).toBeDefined(); }); }); // ------------------------------------------------------------------- // internalError // ------------------------------------------------------------------- describe("internalError()", () => { test("returns status 500", () => { const res = apiResponse.internalError(); expect(res.status).toBe(500); expect(res.successful).toBe(false); expect(res.error).toBe("InternalServerError"); expect(res.message).toContain("Internal Server Error"); }); test("includes meta.timestamp", () => { const res = apiResponse.internalError(); expect(res.meta.timestamp).toBeDefined(); }); }); // ------------------------------------------------------------------- // zodError // ------------------------------------------------------------------- describe("zodError()", () => { test("returns status 400 with parsed error data", () => { const schema = z.object({ name: z.string() }); let zodErr: z.ZodError; try { schema.parse({ name: 123 }); throw new Error("should not reach"); } catch (e) { zodErr = e as z.ZodError; } const res = apiResponse.zodError(zodErr!); expect(res.status).toBe(400); expect(res.successful).toBe(false); expect(res.message).toBe("TypeError"); expect(Array.isArray(res.error)).toBe(true); expect(res.error[0].code).toBe("invalid_type"); }); test("includes meta.timestamp", () => { const schema = z.object({ x: z.string() }); let zodErr: z.ZodError; try { schema.parse({}); throw new Error("should not reach"); } catch (e) { zodErr = e as z.ZodError; } const res = apiResponse.zodError(zodErr!); expect(res.meta.timestamp).toBeDefined(); }); }); });