import { afterEach, describe, expect, it, vi } from "vite-plus/test";import { $createParagraphNode, $createTextNode, $getRoot, $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, createEditor, PASTE_COMMAND,} from "lexical"; import { registerComposerInlineTokenPaste } from "./composerInlineTokenPaste"; class TestClipboardEvent extends Event { readonly clipboardData: DataTransfer; constructor(text: string) { super("paste", { cancelable: true }); this.clipboardData = { files: [], getData: (type: string) => (type === "text/plain" ? text : ""), } as unknown as DataTransfer; }} describe("registerComposerInlineTokenPaste", () => { afterEach(() => { vi.unstubAllGlobals(); }); it("handles a copied mention without also running the plain-text paste fallback", () => { vi.stubGlobal("ClipboardEvent", TestClipboardEvent); const editor = createEditor(); const mention = "[improve-deploy-error-logging.md](.changeset/improve-deploy-error-logging.md)"; const plainTextFallback = vi.fn(() => { const selection = $getSelection(); if (!$isRangeSelection(selection)) return false; selection.insertText(mention); return true; }); editor.update( () => { const paragraph = $createParagraphNode(); $getRoot().append(paragraph); paragraph.selectEnd(); }, { discrete: true }, ); registerComposerInlineTokenPaste(editor, { createMentionNode: (path) => $createTextNode(`<mention:${path}>`), getExpandedAbsoluteOffsetForPoint: () => 0, }); editor.registerCommand(PASTE_COMMAND, plainTextFallback, COMMAND_PRIORITY_EDITOR); const event = new TestClipboardEvent(mention); let handled = false; editor.update( () => { handled = editor.dispatchCommand(PASTE_COMMAND, event as ClipboardEvent); }, { discrete: true }, ); expect(handled).toBe(true); expect(plainTextFallback).not.toHaveBeenCalled(); expect(event.defaultPrevented).toBe(true); expect(editor.getEditorState().read(() => $getRoot().getTextContent())).toBe( "<mention:.changeset/improve-deploy-error-logging.md> ", ); }); it.each([ "yarn expo install @expo/ui", "npm install @jane/foo.js", "import '@scope/pkg/sub/path'", ])("leaves scoped package command %s to the plain-text paste fallback", (command) => { vi.stubGlobal("ClipboardEvent", TestClipboardEvent); const editor = createEditor(); const plainTextFallback = vi.fn((event: ClipboardEvent) => { const selection = $getSelection(); if (!$isRangeSelection(selection)) return false; selection.insertText(event.clipboardData?.getData("text/plain") ?? ""); return true; }); editor.update( () => { const paragraph = $createParagraphNode(); $getRoot().append(paragraph); paragraph.selectEnd(); }, { discrete: true }, ); registerComposerInlineTokenPaste(editor, { createMentionNode: (path) => $createTextNode(`<mention:${path}>`), getExpandedAbsoluteOffsetForPoint: () => 0, }); editor.registerCommand(PASTE_COMMAND, plainTextFallback, COMMAND_PRIORITY_EDITOR); const event = new TestClipboardEvent(command); let handled = false; editor.update( () => { handled = editor.dispatchCommand(PASTE_COMMAND, event as ClipboardEvent); }, { discrete: true }, ); expect(handled).toBe(true); expect(plainTextFallback).toHaveBeenCalledOnce(); expect(editor.getEditorState().read(() => $getRoot().getTextContent())).toBe(command); }); it("pastes a canonical scoped folder link as a mention", () => { vi.stubGlobal("ClipboardEvent", TestClipboardEvent); const editor = createEditor(); const mention = "[sub](@scope/pkg/sub)"; const plainTextFallback = vi.fn(() => true); editor.update( () => { const paragraph = $createParagraphNode(); $getRoot().append(paragraph); paragraph.selectEnd(); }, { discrete: true }, ); registerComposerInlineTokenPaste(editor, { createMentionNode: (path) => $createTextNode(`<mention:${path}>`), getExpandedAbsoluteOffsetForPoint: () => 0, }); editor.registerCommand(PASTE_COMMAND, plainTextFallback, COMMAND_PRIORITY_EDITOR); const event = new TestClipboardEvent(mention); let handled = false; editor.update( () => { handled = editor.dispatchCommand(PASTE_COMMAND, event as ClipboardEvent); }, { discrete: true }, ); expect(handled).toBe(true); expect(plainTextFallback).not.toHaveBeenCalled(); expect(event.defaultPrevented).toBe(true); expect(editor.getEditorState().read(() => $getRoot().getTextContent())).toBe( "<mention:@scope/pkg/sub> ", ); });});
import { afterEach, describe, expect, it, vi } from "vite-plus/test";
import {
$createParagraphNode,
$createTextNode,
$getRoot,
$getSelection,
$isRangeSelection,
COMMAND_PRIORITY_EDITOR,
createEditor,
PASTE_COMMAND,
} from "lexical";
import { registerComposerInlineTokenPaste } from "./composerInlineTokenPaste";
class TestClipboardEvent extends Event {
readonly clipboardData: DataTransfer;
constructor(text: string) {
super("paste", { cancelable: true });
this.clipboardData = {
files: [],
getData: (type: string) => (type === "text/plain" ? text : ""),
} as unknown as DataTransfer;
}
}
describe("registerComposerInlineTokenPaste", () => {
afterEach(() => {
vi.unstubAllGlobals();
});
it("handles a copied mention without also running the plain-text paste fallback", () => {
vi.stubGlobal("ClipboardEvent", TestClipboardEvent);
const editor = createEditor();
const mention = "[improve-deploy-error-logging.md](.changeset/improve-deploy-error-logging.md)";
const plainTextFallback = vi.fn(() => {
const selection = $getSelection();
if (!$isRangeSelection(selection)) return false;
selection.insertText(mention);
return true;
});
editor.update(
() => {
const paragraph = $createParagraphNode();
$getRoot().append(paragraph);
paragraph.selectEnd();
},
{ discrete: true },
);
registerComposerInlineTokenPaste(editor, {
createMentionNode: (path) => $createTextNode(`<mention:${path}>`),
getExpandedAbsoluteOffsetForPoint: () => 0,
});
editor.registerCommand(PASTE_COMMAND, plainTextFallback, COMMAND_PRIORITY_EDITOR);
const event = new TestClipboardEvent(mention);
let handled = false;
editor.update(
() => {
handled = editor.dispatchCommand(PASTE_COMMAND, event as ClipboardEvent);
},
{ discrete: true },
);
expect(handled).toBe(true);
expect(plainTextFallback).not.toHaveBeenCalled();
expect(event.defaultPrevented).toBe(true);
expect(editor.getEditorState().read(() => $getRoot().getTextContent())).toBe(
"<mention:.changeset/improve-deploy-error-logging.md> ",
);
});
it.each([
"yarn expo install @expo/ui",
"npm install @jane/foo.js",
"import '@scope/pkg/sub/path'",
])("leaves scoped package command %s to the plain-text paste fallback", (command) => {
vi.stubGlobal("ClipboardEvent", TestClipboardEvent);
const editor = createEditor();
const plainTextFallback = vi.fn((event: ClipboardEvent) => {
const selection = $getSelection();
if (!$isRangeSelection(selection)) return false;
selection.insertText(event.clipboardData?.getData("text/plain") ?? "");
return true;
});
editor.update(
() => {
const paragraph = $createParagraphNode();
$getRoot().append(paragraph);
paragraph.selectEnd();
},
{ discrete: true },
);
registerComposerInlineTokenPaste(editor, {
createMentionNode: (path) => $createTextNode(`<mention:${path}>`),
getExpandedAbsoluteOffsetForPoint: () => 0,
});
editor.registerCommand(PASTE_COMMAND, plainTextFallback, COMMAND_PRIORITY_EDITOR);
const event = new TestClipboardEvent(command);
let handled = false;
editor.update(
() => {
handled = editor.dispatchCommand(PASTE_COMMAND, event as ClipboardEvent);
},
{ discrete: true },
);
expect(handled).toBe(true);
expect(plainTextFallback).toHaveBeenCalledOnce();
expect(editor.getEditorState().read(() => $getRoot().getTextContent())).toBe(command);
});
it("pastes a canonical scoped folder link as a mention", () => {
vi.stubGlobal("ClipboardEvent", TestClipboardEvent);
const editor = createEditor();
const mention = "[sub](@scope/pkg/sub)";
const plainTextFallback = vi.fn(() => true);
editor.update(
() => {
const paragraph = $createParagraphNode();
$getRoot().append(paragraph);
paragraph.selectEnd();
},
{ discrete: true },
);
registerComposerInlineTokenPaste(editor, {
createMentionNode: (path) => $createTextNode(`<mention:${path}>`),
getExpandedAbsoluteOffsetForPoint: () => 0,
});
editor.registerCommand(PASTE_COMMAND, plainTextFallback, COMMAND_PRIORITY_EDITOR);
const event = new TestClipboardEvent(mention);
let handled = false;
editor.update(
() => {
handled = editor.dispatchCommand(PASTE_COMMAND, event as ClipboardEvent);
},
{ discrete: true },
);
expect(handled).toBe(true);
expect(plainTextFallback).not.toHaveBeenCalled();
expect(event.defaultPrevented).toBe(true);
expect(editor.getEditorState().read(() => $getRoot().getTextContent())).toBe(
"<mention:@scope/pkg/sub> ",
);
});
});