227 lines
6.5 KiB
TypeScript
227 lines
6.5 KiB
TypeScript
/**
|
|
* 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();
|
|
});
|
|
});
|
|
});
|