test(ai-toolbar): close remaining modifier and identity gaps

This commit is contained in:
2026-04-23 05:22:57 -04:00
parent 42a888df76
commit 075d88a247

View File

@@ -1,6 +1,7 @@
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"; import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
import * as React from "react"; import * as React from "react";
import { renderToStaticMarkup } from "react-dom/server"; import { renderToStaticMarkup } from "react-dom/server";
import { imageFileKey } from "@/lib/multi-image";
type AIToolbarProps = { type AIToolbarProps = {
adminAiEnabled: boolean; adminAiEnabled: boolean;
@@ -586,6 +587,19 @@ describe("AI toolbar paste capture", () => {
expect(imageTriggerOpen).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 () => { test("Shift+Cmd+A also opens the image picker when the composer is idle", async () => {
const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary(); const { textareaProps, imageTriggerOpen } = await renderToolbarBoundary();
const metaEvent = createTextareaKeydownEvent({ const metaEvent = createTextareaKeydownEvent({
@@ -748,6 +762,69 @@ describe("AI toolbar paste capture", () => {
expect(onImagesSelect).toHaveBeenCalledTimes(1); expect(onImagesSelect).toHaveBeenCalledTimes(1);
}); });
test("Shift+Mod+V does not trigger the async clipboard fallback", async () => {
const onImagesSelect = mock();
const clipboardRead = mock(async () => []);
(globalThis as { navigator?: Navigator }).navigator = {
clipboard: { read: clipboardRead },
} as Navigator;
await renderToolbar({ onImagesSelect });
const handleDocumentKeydown = getDocumentListener("keydown");
await handleDocumentKeydown(
createDocumentKeydownEvent({ ctrlKey: true, shiftKey: true }),
);
expect(clipboardRead).not.toHaveBeenCalled();
expect(onImagesSelect).not.toHaveBeenCalled();
});
test("Alt+Mod+V does not trigger the async clipboard fallback", async () => {
const onImagesSelect = mock();
const clipboardRead = mock(async () => []);
(globalThis as { navigator?: Navigator }).navigator = {
clipboard: { read: clipboardRead },
} as Navigator;
await renderToolbar({ onImagesSelect });
const handleDocumentKeydown = getDocumentListener("keydown");
await handleDocumentKeydown(
createDocumentKeydownEvent({ ctrlKey: true, altKey: true }),
);
expect(clipboardRead).not.toHaveBeenCalled();
expect(onImagesSelect).not.toHaveBeenCalled();
});
test("async clipboard fallback ignores editable targets", async () => {
const onImagesSelect = mock();
const clipboardRead = mock(async () => []);
(globalThis as { navigator?: Navigator }).navigator = {
clipboard: { read: clipboardRead },
} as Navigator;
await renderToolbar({ onImagesSelect });
const handleDocumentKeydown = getDocumentListener("keydown");
await handleDocumentKeydown(
createDocumentKeydownEvent({
ctrlKey: true,
target: { tagName: "DIV", isContentEditable: true },
}),
);
expect(clipboardRead).not.toHaveBeenCalled();
expect(onImagesSelect).not.toHaveBeenCalled();
});
test("Ctrl+Meta+V does not trigger the async clipboard fallback", async () => { test("Ctrl+Meta+V does not trigger the async clipboard fallback", async () => {
const onImagesSelect = mock(); const onImagesSelect = mock();
const clipboardRead = mock(async () => []); const clipboardRead = mock(async () => []);
@@ -918,6 +995,9 @@ describe("AI toolbar paste capture", () => {
expect(syncOnImagesSelect.mock.calls[0]?.[0][0]?.lastModified).toBe( expect(syncOnImagesSelect.mock.calls[0]?.[0][0]?.lastModified).toBe(
asyncOnImagesSelect.mock.calls[0]?.[0][0]?.lastModified, asyncOnImagesSelect.mock.calls[0]?.[0][0]?.lastModified,
); );
expect(
imageFileKey(syncOnImagesSelect.mock.calls[0]?.[0][0]),
).toBe(imageFileKey(asyncOnImagesSelect.mock.calls[0]?.[0][0]));
}); });
test("async clipboard fallback does not double-handle a paste already handled by the synchronous document paste flow", async () => { test("async clipboard fallback does not double-handle a paste already handled by the synchronous document paste flow", async () => {