Files
local-cal/tests/ai-toolbar-shortcuts.test.ts

214 lines
5.8 KiB
TypeScript

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("");
});
});