File
Blob: tests/shared/editor-headless.test.ts
| 1 | import { readdirSync, readFileSync, statSync } from "node:fs"; |
| 2 | import { fileURLToPath, URL } from "node:url"; |
| 3 | import { describe, expect, it } from "vitest"; |
| 4 | import { getSchema } from "@tiptap/core"; |
| 5 | import { countCharacters, countWords, createHeadlessEditorExtensions } from "@/shared/editor/schema"; |
| 6 | |
| 7 | const SHARED_EDITOR_SCHEMA_DIR = fileURLToPath(new URL("../../src/shared/editor/schema/", import.meta.url)); |
| 8 | |
| 9 | function listSourceFiles(dir: string): string[] { |
| 10 | const files: string[] = []; |
| 11 | for (const entry of readdirSync(dir)) { |
| 12 | const path = `${dir}${entry}`; |
| 13 | const stat = statSync(path); |
| 14 | if (stat.isDirectory()) { |
| 15 | files.push(...listSourceFiles(`${path}/`)); |
| 16 | continue; |
| 17 | } |
| 18 | if (entry.endsWith(".ts") || entry.endsWith(".tsx")) { |
| 19 | files.push(path); |
| 20 | } |
| 21 | } |
| 22 | return files; |
| 23 | } |
| 24 | |
| 25 | describe("headless shared editor schema", () => { |
| 26 | it("imports in the Node shared test runtime without a browser global", () => { |
| 27 | expect((globalThis as { document?: unknown }).document).toBeUndefined(); |
| 28 | const schema = getSchema(createHeadlessEditorExtensions()); |
| 29 | |
| 30 | expect(schema.nodes.callout).toBeDefined(); |
| 31 | expect(schema.nodes.codeBlock).toBeDefined(); |
| 32 | expect(schema.nodes.image).toBeDefined(); |
| 33 | expect(schema.nodes.pageMention).toBeDefined(); |
| 34 | expect(schema.nodes.details).toBeDefined(); |
| 35 | expect(schema.nodes.table).toBeDefined(); |
| 36 | }); |
| 37 | |
| 38 | it("keeps the shared schema entrypoint free of client and React imports", () => { |
| 39 | const forbidden = [ |
| 40 | /@\/client/, |
| 41 | /@tiptap\/react/, |
| 42 | /from\s+["']react["']/, |
| 43 | /\.css["']/, |
| 44 | /\bwindow\./, |
| 45 | /\bdocument\./, |
| 46 | /\bHTMLElement\b/, |
| 47 | /\bNodeView\b/, |
| 48 | ]; |
| 49 | |
| 50 | for (const file of listSourceFiles(SHARED_EDITOR_SCHEMA_DIR)) { |
| 51 | const source = readFileSync(file, "utf8"); |
| 52 | for (const pattern of forbidden) { |
| 53 | expect(source, `${file} should not match ${pattern}`).not.toMatch(pattern); |
| 54 | } |
| 55 | } |
| 56 | }); |
| 57 | |
| 58 | it("exports the document metric helpers used by the editor", () => { |
| 59 | expect(countWords(" one two\nthree ")).toBe(3); |
| 60 | expect(countCharacters("a😀")).toBe(2); |
| 61 | }); |
| 62 | }); |