/** * Which failures a user can act on, and which just need reporting. */ import { test } from "node:test"; import assert from "node:assert/strict"; import { CONTACT, ImpossibleRequest, NO_CARD, NO_GREETING, SuckerError, TOO_FEW_MESSAGES, TRUNCATED_CARD, isImpossibleRequest, isSuckerError, userFacingMessage, } from "../src/lib/errors.ts"; test("the one fixable failure is shown as written, with the advice that fixes it", () => { assert.equal(userFacingMessage(TRUNCATED_CARD), TRUNCATED_CARD.message); assert.match(TRUNCATED_CARD.message, /Context Size/); assert.ok(TRUNCATED_CARD.message.includes(CONTACT)); }); test("shapes Janitor cannot produce never tell the user to fix them", () => { for (const e of [NO_CARD, NO_GREETING, TOO_FEW_MESSAGES]) { const msg = userFacingMessage(e); assert.match(msg, /not your fault and there is nothing for you to fix/i); assert.ok(msg.includes(CONTACT), "must say where to report it"); // The old failure mode: instructions for something they cannot do. assert.ok(!/open the chat|try again|point sucker/i.test(msg), `actionable advice leaked into: ${msg}`); } }); test("the report carries which assumption broke, so it is useful", () => { assert.match(userFacingMessage(NO_GREETING), /\(no greeting in the request\)/); assert.match(userFacingMessage(NO_CARD), /\(no system message in the request\)/); assert.match(userFacingMessage(TOO_FEW_MESSAGES), /\(fewer than two messages/); }); test("a genuine bug reports itself without leaking internals", () => { const msg = userFacingMessage(new TypeError("Cannot read properties of undefined")); assert.match(msg, /not your fault/i); assert.ok(msg.includes(CONTACT)); assert.ok(!msg.includes("Cannot read properties")); assert.ok(!/\($/.test(msg.trim()), "no empty detail parenthesis"); }); test("nobody is called a dingus", () => { for (const e of [TRUNCATED_CARD, NO_CARD, NO_GREETING, TOO_FEW_MESSAGES, new Error("x")]) { assert.ok(!/dingus/i.test(userFacingMessage(e))); } }); test("classified across module boundaries, not just by identity", () => { assert.ok(isSuckerError(new SuckerError("x"))); assert.ok(isSuckerError({ name: "SuckerError", message: "x" })); assert.ok(isImpossibleRequest(new ImpossibleRequest("x"))); assert.ok(isImpossibleRequest({ name: "ImpossibleRequest", detail: "x" })); assert.ok(!isSuckerError(new Error("x"))); assert.ok(!isImpossibleRequest(new SuckerError("x"))); assert.ok(!isSuckerError(null)); });