import { describe, expect, it } from "@suaveplan/testing/runner"; import { HIBP_CODES } from "../error-codes.js"; import { HibpError } from "./hibp-error.js"; describe("HibpError", () => { it("carries the code and message", { timeout: 5000 }, () => { const err = new HibpError(HIBP_CODES.NOT_FOUND, "missing"); expect(err.code).toBe(HIBP_CODES.NOT_FOUND); expect(err.message).toContain("missing"); expect(err.name).toBe("HibpError"); }); it("threads cause and context", { timeout: 5000 }, () => { const cause = new Error("boom"); const err = new HibpError(HIBP_CODES.NETWORK_ERROR, "wrap", { cause, context: { url: "https://example.com" }, traceId: "t-1", }); expect(err.cause).toBe(cause); expect(err.context).toEqual({ url: "https://example.com" }); expect(err.traceId).toBe("t-1"); }); it("JSON form omits api key, email, password, and full hash", { timeout: 5000, }, () => { const sha = "F3BBBE3A5FA0E1E81F4D9F3CC0E9D5B5B69E9C4F"; const err = new HibpError( HIBP_CODES.NETWORK_ERROR, `failed for user@example.com with hash ${sha} and key k_test`, { leakClass: "sha1" } ); const json = JSON.stringify(err.toJSON()); expect(json).not.toContain(sha); expect(json).not.toContain("user@example.com"); expect(json).toContain("HIBP.NETWORK_ERROR"); expect(json).toContain("[redacted]"); }); it("threads injectable clock", { timeout: 5000 }, () => { const err = new HibpError(HIBP_CODES.ABORTED, "x", { clock: () => 12345, }); expect(err.timestamp).toBe(12345); }); it("omits leakClass from JSON when absent", { timeout: 5000 }, () => { const err = new HibpError(HIBP_CODES.NOT_FOUND, "x"); const json = err.toJSON(); expect(json.leakClass).toBeUndefined(); }); });