Skip to content
File

Blob: tests/shared/editor-headless.test.ts

typescript63 lines
1import { readdirSync, readFileSync, statSync } from "node:fs";
2import { fileURLToPath, URL } from "node:url";
3import { describe, expect, it } from "vitest";
4import { getSchema } from "@tiptap/core";
5import { countCharacters, countWords, createHeadlessEditorExtensions } from "@/shared/editor/schema";
6 
7const SHARED_EDITOR_SCHEMA_DIR = fileURLToPath(new URL("../../src/shared/editor/schema/", import.meta.url));
8 
9function 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 
25describe("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});