import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { toast } from "sonner"; import { NOTICE_DURATION_MS, TOASTER_LABEL, liftToastsAboveModal, notifyError, notifyInfo, notifySuccess } from "../src/lib/notify.ts"; // 提示与报错改 toast (2026-09-30): one helper, top centre, 3s / 6s + close. const read = (path: string) => readFileSync(new URL(path, import.meta.url), "utf8"); test("success and info leave after 3s; errors stay 6s with a close button; blank messages raise nothing", () => { const calls: Array<[string, string, Record]> = []; const before = { success: toast.success, info: toast.info, error: toast.error }; toast.success = (message, options) => { calls.push(["success", String(message), options as Record]); return 1; }; toast.info = (message, options) => { calls.push(["info", String(message), options as Record]); return 1; }; toast.error = (message, options) => { calls.push(["error", String(message), options as Record]); return 1; }; try { notifySuccess("已保存。"); notifyInfo("请输入验证器动态码", { id: "auth-notice" }); notifyError("保存失败,请重试"); notifyError(" "); assert.deepEqual(calls, [ ["success", "已保存。", { duration: 3_000 }], ["info", "请输入验证器动态码", { duration: 3_000, id: "auth-notice" }], ["error", "保存失败,请重试", { duration: 6_000, closeButton: true }], ]); assert.deepEqual(NOTICE_DURATION_MS, { success: 3_000, info: 3_000, error: 6_000 }); } finally { Object.assign(toast, before); } }); test("the toaster sits top centre with the notch offset, and lifting is a no-op without a DOM", () => { const toaster = read("../src/components/ui/sonner.tsx"); assert.match(toaster, /position="top-center"/); assert.match(toaster, /containerAriaLabel=\{TOASTER_LABEL\}/); assert.match(toaster, /mobileOffset=\{\{ top: "calc\(env\(safe-area-inset-top, 0px\) \+ 12px\)", left: "16px", right: "16px" \}\}/); assert.equal(TOASTER_LABEL, "页面提示"); assert.doesNotThrow(() => liftToastsAboveModal()); const layout = read("../src/app/layout.tsx"); assert.match(layout, //); }); test("no product surface keeps a green success bar", () => { const styles = read("../src/app/globals.css"); assert.doesNotMatch(styles, /\.form-success/); assert.doesNotMatch(styles, /\.form-error[^{]*\{[^}]*border-left/); });