Emdash source with visual editor image upload fix
Fixes: 1. media.ts: wrap placeholder generation in try-catch 2. toolbar.ts: check r.ok, display error message in popover
This commit is contained in:
226
packages/admin/tests/editor/input-rules.test.ts
Normal file
226
packages/admin/tests/editor/input-rules.test.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user