import { describe, expect, it } from "vitest"; import { SLASH_COMMANDS, fuzzyScore, searchSlashCommands, } from "./slash.js"; describe("slash registry", () => { it("has 30 commands with unique ids", () => { expect(SLASH_COMMANDS).toHaveLength(30); const ids = new Set(SLASH_COMMANDS.map((c) => c.id)); expect(ids.size).toBe(30); }); it("every plain command maps to a valid block type", () => { const VALID = new Set([ "paragraph", "heading_1", "heading_2", "heading_3", "quote", "callout", "bulleted_list", "numbered_list", "todo", "toggle", "image", "video", "audio", "file", "bookmark", "embed", "code", "equation", "column", "column_list", "divider", "toc", "spacer", "database", "linked_database", "table", "chart", "form", "synced_block", "child_page", "child_database", ]); for (const c of SLASH_COMMANDS) { if (c.blockType !== undefined) expect(VALID.has(c.blockType)).toBe(true); else expect(c.special).toBeDefined(); } }); }); describe("fuzzyScore", () => { it("scores exact prefix best", () => { expect(fuzzyScore("text", "Text plain paragraph default")).toBe(1); }); it("scores subsequence with gap penalty", () => { const s = fuzzyScore("h1", "Heading 1 subtitle medium"); expect(s).not.toBeNull(); expect(s!).toBeGreaterThan(1); }); it("returns null for non-subsequence", () => { expect(fuzzyScore("zz", "Heading 1")).toBeNull(); }); }); describe("searchSlashCommands", () => { it("empty query returns all commands in menu order", () => { const hits = searchSlashCommands(""); expect(hits).toHaveLength(30); expect(hits[0]?.command.id).toBe("paragraph"); expect(hits.map((h) => h.command.id)).toEqual(SLASH_COMMANDS.map((c) => c.id)); }); it('"h1" ranks Heading 1 first', () => { const hits = searchSlashCommands("h1"); expect(hits.length).toBeGreaterThan(0); expect(hits[0]?.command.id).toBe("heading_1"); }); it('"cal" finds Callout in the top 3', () => { const hits = searchSlashCommands("cal"); const ids = hits.slice(0, 3).map((h) => h.command.id); expect(ids).toContain("callout"); }); it('"emb" finds Embed', () => { const hits = searchSlashCommands("emb"); expect(hits.map((h) => h.command.id)).toContain("embed"); }); it("is deterministic (same query → same order)", () => { const a = searchSlashCommands("list").map((h) => h.command.id); const b = searchSlashCommands("list").map((h) => h.command.id); expect(a).toEqual(b); expect(a.length).toBeGreaterThanOrEqual(2); }); });