Files
calendar/packages/trpc/server/createNextApiHandler.test.ts
T

173 lines
4.3 KiB
TypeScript

import { captureException } from "@sentry/nextjs";
import type { NextApiRequest } from "next";
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import type { ZodIssue } from "zod";
import { ZodError } from "zod";
import { TRPCError } from "@trpc/server";
import type { AnyRouter } from "@trpc/server";
import { createNextApiHandler } from "./createNextApiHandler";
import { errorFormatter } from "./errorFormatter";
import { onErrorHandler } from "./onErrorHandler";
vi.mock("@sentry/nextjs", () => ({
captureException: vi.fn(),
}));
describe("createNextApiHandler", () => {
const mockRouter = {
createCaller: vi.fn(),
_def: {
procedures: {},
middleware: [],
contextOptions: {},
},
} as unknown as AnyRouter;
const mockReq = {
method: "POST",
url: "/api/trpc/test",
} as NextApiRequest;
let consoleSpy: ReturnType<typeof vi.spyOn>;
beforeEach(() => {
consoleSpy = vi.spyOn(console, "error").mockImplementation(() => undefined);
vi.clearAllMocks();
});
afterEach(() => {
consoleSpy.mockRestore();
});
describe("error formatting", () => {
it("should format ZodError as BAD_REQUEST", () => {
const zodError = new ZodError([
{
path: ["name"],
message: "Required",
code: "invalid_type",
expected: "string",
received: "undefined",
} as ZodIssue,
]);
const error = new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Internal Server Error",
cause: zodError,
});
const result = errorFormatter({
shape: {
message: "Internal Server Error",
code: 500,
data: {
code: "INTERNAL_SERVER_ERROR",
httpStatus: 500,
path: "test",
},
},
error,
type: "query",
path: "test",
input: undefined,
ctx: undefined,
});
expect(result).toEqual({
message: "Invalid input",
code: 400,
data: {
code: "BAD_REQUEST",
httpStatus: 400,
path: "test",
zodError: {
formErrors: [],
fieldErrors: {
name: ["Required"],
},
},
},
});
});
it("should not modify non-ZodError errors", () => {
const baseError = new Error("Database connection failed");
const error = new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Internal Server Error",
cause: baseError,
});
const shape = {
message: "Internal Server Error",
code: 500,
data: {
code: "INTERNAL_SERVER_ERROR",
httpStatus: 500,
path: "test",
},
};
const result = errorFormatter({
shape,
error,
type: "query",
path: "test",
input: undefined,
ctx: undefined,
});
expect(result).toEqual(shape);
});
});
describe("error handling", () => {
it("should handle TRPC errors correctly", () => {
const handler = createNextApiHandler(mockRouter);
const error = new TRPCError({ code: "BAD_REQUEST", message: "Invalid input" });
onErrorHandler({
error,
req: mockReq,
});
expect(captureException).not.toHaveBeenCalled();
expect(consoleSpy).not.toHaveBeenCalled();
});
it("should handle internal server errors correctly", () => {
const handler = createNextApiHandler(mockRouter);
const baseError = new Error("Database connection failed");
const error = new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Internal Server Error",
cause: baseError,
});
onErrorHandler({
error,
req: mockReq,
});
expect(consoleSpy).toHaveBeenCalledWith("Something went wrong", error);
expect(captureException).toHaveBeenCalledWith(error);
});
it("should not log client errors", () => {
const handler = createNextApiHandler(mockRouter);
const error = new TRPCError({ code: "BAD_REQUEST", message: "Invalid input" });
onErrorHandler({
error,
req: mockReq,
});
expect(consoleSpy).not.toHaveBeenCalled();
expect(captureException).not.toHaveBeenCalled();
});
});
});