/** * Input Rules Tests for TipTap Editor * * Tests that Markdown-style shortcuts work correctly in the editor. * * TipTap input rules are triggered by actual text input, not insertContent(). * In headless tests, we simulate this by using the inputRules extension's * run function or by testing the resulting transformations. * * For integration testing, we verify the editor has the correct extensions * configured and that the expected node/mark types exist. */ import { Editor } from "@tiptap/core"; import Typography from "@tiptap/extension-typography"; import StarterKit from "@tiptap/starter-kit"; import { describe, it, expect, beforeEach, afterEach } from "vitest"; describe("Editor Input Rules", () => { let editor: Editor; beforeEach(() => { editor = new Editor({ extensions: [ StarterKit.configure({ heading: { levels: [1, 2, 3] }, }), Typography, ], content: "", }); }); afterEach(() => { editor.destroy(); }); describe("Editor extension configuration", () => { it("has heading extension with levels 1-3", () => { const headingExtension = editor.extensionManager.extensions.find( (ext) => ext.name === "heading", ); expect(headingExtension).toBeDefined(); }); it("has bulletList extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "bulletList"); expect(extension).toBeDefined(); }); it("has orderedList extension", () => { const extension = editor.extensionManager.extensions.find( (ext) => ext.name === "orderedList", ); expect(extension).toBeDefined(); }); it("has blockquote extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "blockquote"); expect(extension).toBeDefined(); }); it("has codeBlock extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "codeBlock"); expect(extension).toBeDefined(); }); it("has horizontalRule extension", () => { const extension = editor.extensionManager.extensions.find( (ext) => ext.name === "horizontalRule", ); expect(extension).toBeDefined(); }); it("has bold extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "bold"); expect(extension).toBeDefined(); }); it("has italic extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "italic"); expect(extension).toBeDefined(); }); it("has code extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "code"); expect(extension).toBeDefined(); }); it("has strike extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "strike"); expect(extension).toBeDefined(); }); it("has typography extension", () => { const extension = editor.extensionManager.extensions.find((ext) => ext.name === "typography"); expect(extension).toBeDefined(); }); }); describe("Commands work correctly", () => { it("can toggle heading 1", () => { editor.commands.setHeading({ level: 1 }); expect(editor.isActive("heading", { level: 1 })).toBe(true); }); it("can toggle heading 2", () => { editor.commands.setHeading({ level: 2 }); expect(editor.isActive("heading", { level: 2 })).toBe(true); }); it("can toggle heading 3", () => { editor.commands.setHeading({ level: 3 }); expect(editor.isActive("heading", { level: 3 })).toBe(true); }); it("can toggle bullet list", () => { editor.commands.toggleBulletList(); expect(editor.isActive("bulletList")).toBe(true); }); it("can toggle ordered list", () => { editor.commands.toggleOrderedList(); expect(editor.isActive("orderedList")).toBe(true); }); it("can toggle blockquote", () => { editor.commands.toggleBlockquote(); expect(editor.isActive("blockquote")).toBe(true); }); it("can toggle code block", () => { editor.commands.toggleCodeBlock(); expect(editor.isActive("codeBlock")).toBe(true); }); it("can insert horizontal rule", () => { editor.commands.setHorizontalRule(); const json = editor.getJSON(); const hasHR = json.content?.some((node) => node.type === "horizontalRule"); expect(hasHR).toBe(true); }); it("can toggle bold", () => { editor.commands.insertContent("test"); editor.commands.selectAll(); editor.commands.toggleBold(); expect(editor.isActive("bold")).toBe(true); }); it("can toggle italic", () => { editor.commands.insertContent("test"); editor.commands.selectAll(); editor.commands.toggleItalic(); expect(editor.isActive("italic")).toBe(true); }); it("can toggle code", () => { editor.commands.insertContent("test"); editor.commands.selectAll(); editor.commands.toggleCode(); expect(editor.isActive("code")).toBe(true); }); it("can toggle strike", () => { editor.commands.insertContent("test"); editor.commands.selectAll(); editor.commands.toggleStrike(); expect(editor.isActive("strike")).toBe(true); }); }); describe("Schema has correct node types", () => { it("has heading node type", () => { expect(editor.schema.nodes.heading).toBeDefined(); }); it("has bulletList node type", () => { expect(editor.schema.nodes.bulletList).toBeDefined(); }); it("has orderedList node type", () => { expect(editor.schema.nodes.orderedList).toBeDefined(); }); it("has blockquote node type", () => { expect(editor.schema.nodes.blockquote).toBeDefined(); }); it("has codeBlock node type", () => { expect(editor.schema.nodes.codeBlock).toBeDefined(); }); it("has horizontalRule node type", () => { expect(editor.schema.nodes.horizontalRule).toBeDefined(); }); }); describe("Schema has correct mark types", () => { it("has bold mark type", () => { expect(editor.schema.marks.bold).toBeDefined(); }); it("has italic mark type", () => { expect(editor.schema.marks.italic).toBeDefined(); }); it("has code mark type", () => { expect(editor.schema.marks.code).toBeDefined(); }); it("has strike mark type", () => { expect(editor.schema.marks.strike).toBeDefined(); }); }); describe("Input rules are registered", () => { it("has input rules plugin", () => { // StarterKit registers input rules through individual extensions // We verify by checking extensions have inputRules defined const extensions = editor.extensionManager.extensions; const headingExt = extensions.find((e) => e.name === "heading"); expect(headingExt).toBeDefined(); }); }); });