/** * @file Tests for the shared UI primitives: the toast queue (errors stay, * successes fade, duplicates collapse), promise confirms (a second ask cancels * the first) and the IME-aware Enter check. * * @author Nguyễn Ngọc Trí Vĩ */ import { afterEach, describe, expect, it, vi } from "vitest"; import { dismissToast, subscribeToasts, toast, type ToastItem } from "../toast"; import { confirmDialog, settleConfirm, subscribeConfirm } from "../confirm"; import { isSubmitEnter } from "../keys"; afterEach(() => vi.useRealTimers()); describe("toast", () => { it("keeps an error, fades a success, collapses a repeat", () => { vi.useFakeTimers(); let seen: ToastItem[] = []; const off = subscribeToasts((i) => (seen = i)); const errId = toast.error(new Error("boom")); toast.success("saved"); toast.success("saved"); expect(seen.map((t) => t.message)).toEqual(["boom", "saved"]); vi.advanceTimersByTime(5000); expect(seen.map((t) => t.message)).toEqual(["boom"]); dismissToast(errId); expect(seen).toEqual([]); off(); }); }); describe("confirmDialog", () => { it("resolves on settle and cancels an earlier pending ask", async () => { const off = subscribeConfirm(() => {}); const first = confirmDialog({ title: "a" }); const second = confirmDialog({ title: "b" }); await expect(first).resolves.toBe(false); settleConfirm(true); await expect(second).resolves.toBe(true); off(); }); }); describe("isSubmitEnter", () => { const ev = (o: Partial) => ({ key: "Enter", shiftKey: false, isComposing: false, keyCode: 13, ...o }) as KeyboardEvent; it("submits a plain Enter only", () => { expect(isSubmitEnter(ev({}))).toBe(true); expect(isSubmitEnter(ev({ shiftKey: true }))).toBe(false); expect(isSubmitEnter(ev({ isComposing: true }))).toBe(false); expect(isSubmitEnter(ev({ keyCode: 229 }))).toBe(false); expect(isSubmitEnter(ev({ key: "a" }))).toBe(false); }); });