import { describe, expect, mock, test } from "bun:test"; import { createTextareaKeydownEvent, registerAIToolbarMarkupHooks, renderToolbarBoundary, } from "./helpers/ai-toolbar-test-helpers"; registerAIToolbarMarkupHooks(); describe("AI toolbar keyboard shortcuts", () => { test("Ctrl+Enter triggers AI generation when the prompt has content", async () => { const onAiCreate = mock(); const { textareaProps } = await renderToolbarBoundary({ aiPrompt: "Draft a kickoff", onAiCreate, }); const event = createTextareaKeydownEvent({ ctrlKey: true }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).toHaveBeenCalledTimes(1); expect(onAiCreate).toHaveBeenCalledTimes(1); }); test("Cmd+Enter triggers AI generation when images are attached", async () => { const onAiCreate = mock(); const { textareaProps } = await renderToolbarBoundary({ imagePreviews: ["blob:first"], onAiCreate, }); const event = createTextareaKeydownEvent({ metaKey: true }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).toHaveBeenCalledTimes(1); expect(onAiCreate).toHaveBeenCalledTimes(1); }); test("Mod+Enter ignores extra modifiers so Shift+Ctrl+Enter does not generate", async () => { const onAiCreate = mock(); const { textareaProps } = await renderToolbarBoundary({ aiPrompt: "Draft a kickoff", onAiCreate, }); const event = createTextareaKeydownEvent({ ctrlKey: true, shiftKey: true, }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(onAiCreate).not.toHaveBeenCalled(); }); test("Mod+Enter ignores combined Ctrl+Meta modifiers", async () => { const onAiCreate = mock(); const { textareaProps } = await renderToolbarBoundary({ aiPrompt: "Draft a kickoff", onAiCreate, }); const event = createTextareaKeydownEvent({ ctrlKey: true, metaKey: true, }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(onAiCreate).not.toHaveBeenCalled(); }); test("Mod+Enter ignores Alt-modified submissions", async () => { const onAiCreate = mock(); const { textareaProps } = await renderToolbarBoundary({ aiPrompt: "Draft a kickoff", onAiCreate, }); const event = createTextareaKeydownEvent({ ctrlKey: true, altKey: true, }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(onAiCreate).not.toHaveBeenCalled(); }); test("Mod+Enter does not trigger AI generation while loading", async () => { const onAiCreate = mock(); const { textareaProps } = await renderToolbarBoundary({ aiPrompt: "Draft a kickoff", aiLoading: true, onAiCreate, }); const event = createTextareaKeydownEvent({ ctrlKey: true }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(onAiCreate).not.toHaveBeenCalled(); }); test("Shift+Mod+A opens the image picker when the composer is idle", async () => { const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary(); const ctrlEvent = createTextareaKeydownEvent({ key: "A", ctrlKey: true, shiftKey: true, }); textareaProps.onKeyDown?.(ctrlEvent); expect(ctrlEvent.preventDefault).toHaveBeenCalledTimes(1); expect(imageTriggerOpen).toHaveBeenCalledTimes(1); }); test("Mod+A without Shift does not open the image picker", async () => { const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary(); const event = createTextareaKeydownEvent({ key: "A", ctrlKey: true, }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(imageTriggerOpen).not.toHaveBeenCalled(); }); test("Shift+Cmd+A also opens the image picker when the composer is idle", async () => { const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary(); const metaEvent = createTextareaKeydownEvent({ key: "A", metaKey: true, shiftKey: true, }); textareaProps.onKeyDown?.(metaEvent); expect(metaEvent.preventDefault).toHaveBeenCalledTimes(1); expect(imageTriggerOpen).toHaveBeenCalledTimes(1); }); test("Shift+Mod+A ignores Alt-modified submissions", async () => { const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary(); const event = createTextareaKeydownEvent({ key: "A", ctrlKey: true, shiftKey: true, altKey: true, }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(imageTriggerOpen).not.toHaveBeenCalled(); }); test("Shift+Mod+A ignores combined Ctrl+Meta modifiers", async () => { const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary(); const event = createTextareaKeydownEvent({ key: "A", ctrlKey: true, metaKey: true, shiftKey: true, }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).not.toHaveBeenCalled(); expect(imageTriggerOpen).not.toHaveBeenCalled(); }); test("Shift+Mod+A stays disabled while generation is in progress", async () => { const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary({ aiLoading: true, }); const ctrlEvent = createTextareaKeydownEvent({ key: "A", ctrlKey: true, shiftKey: true, }); textareaProps.onKeyDown?.(ctrlEvent); expect(ctrlEvent.preventDefault).not.toHaveBeenCalled(); expect(imageTriggerOpen).not.toHaveBeenCalled(); }); test("Escape clears the prompt when the textarea has content", async () => { const setAiPrompt = mock(); const { textareaProps } = await renderToolbarBoundary({ aiPrompt: "Draft a kickoff", setAiPrompt, }); const event = createTextareaKeydownEvent({ key: "Escape" }); textareaProps.onKeyDown?.(event); expect(event.preventDefault).toHaveBeenCalledTimes(1); expect(setAiPrompt).toHaveBeenCalledTimes(1); expect(setAiPrompt).toHaveBeenCalledWith(""); }); });