import { describe, expect, spyOn, test } from "bun:test";
import { notFound, redirect } from "@tanstack/react-router";
import { clientSafeError } from "./client-safe-error";
import { HttpError } from "./errors";
describe("clientSafeError (DEPLOY-P8)", () => {
test("unknown errors become a generic 500 and are logged", () => {
const log = spyOn(console, "error").mockImplementation(() => undefined);
const masked = clientSafeError(new Error("D1_ERROR: no such column secret_hash"));
expect(masked).toBeInstanceOf(HttpError);
expect(masked instanceof HttpError && masked.status).toBe(500);
expect(masked instanceof HttpError && masked.message).toBe("Internal error");
expect(log).toHaveBeenCalled();
log.mockRestore();
});
test("5xx HttpErrors lose their internal message", () => {
const log = spyOn(console, "error").mockImplementation(() => undefined);
const result = clientSafeError(new HttpError(500, "D1 table x missing"));
expect(result instanceof HttpError && [result.status, result.message]).toEqual([500, "Internal error"]);
log.mockRestore();
});
test("deliberate errors and router control flow pass through", () => {
const http = new HttpError(403, "Nope");
expect(clientSafeError(http)).toBe(http);
const nf = notFound();
expect(clientSafeError(nf)).toBe(nf);
const to = redirect({ to: "/" });
expect(clientSafeError(to)).toBe(to);
});
test("validation failures become a 400 with the first issue's message", () => {
const error = Object.assign(new Error("[...]"), { name: "ZodError", issues: [{ message: "Too long" }] });
const result = clientSafeError(error);
expect(result instanceof HttpError && [result.status, result.message]).toEqual([400, "Too long"]);
});
test("validator failures serialized into a plain Error message also become a 400", () => {
const issues = [{ code: "invalid_value", path: ["acceptTerms"], message: "Accept the Terms to continue" }];