Skip to content
File

Blob: tests/client/components/editor/controllers/details-block.test.ts

typescript87 lines
1import { describe, expect, it } from "vitest";
2import { getSchema } from "@tiptap/core";
3import { StarterKit } from "@tiptap/starter-kit";
4import { EditorState, TextSelection } from "@tiptap/pm/state";
5import {
6 applyMoveToDetailsContent,
7 createDetailsBlockNode,
8 DEFAULT_DETAILS_SUMMARY,
9 DETAILS_SUMMARY_PLACEHOLDER,
10} from "@/client/components/editor/controllers/details-block";
11import { DetailsBlockExtensions } from "@/client/components/editor/extensions/details-block";
12 
13const schema = getSchema([StarterKit.configure({ undoRedo: false }), ...DetailsBlockExtensions]);
14 
15describe("details block helpers", () => {
16 it("leaves the summary empty by default so the placeholder can guide the title field", () => {
17 expect(createDetailsBlockNode()).toEqual({
18 type: "details",
19 attrs: { open: true },
20 content: [
21 {
22 type: "detailsSummary",
23 },
24 {
25 type: "detailsContent",
26 content: [{ type: "paragraph" }],
27 },
28 ],
29 });
30 });
31 
32 it("still preserves an explicit summary when one is provided", () => {
33 expect(createDetailsBlockNode({ summary: "Specs" })).toEqual({
34 type: "details",
35 attrs: { open: true },
36 content: [
37 {
38 type: "detailsSummary",
39 content: [{ type: "text", text: "Specs" }],
40 },
41 {
42 type: "detailsContent",
43 content: [{ type: "paragraph" }],
44 },
45 ],
46 });
47 });
48 
49 it("keeps the human-readable fallback label and a separate summary placeholder", () => {
50 expect(DEFAULT_DETAILS_SUMMARY).toBe("Details");
51 expect(DETAILS_SUMMARY_PLACEHOLDER).toBe("Summary");
52 });
53 
54 it("moves an empty summary selection into the details content", () => {
55 const doc = schema.nodeFromJSON({
56 type: "doc",
57 content: [createDetailsBlockNode()],
58 });
59 const state = EditorState.create({
60 schema,
61 doc,
62 selection: TextSelection.create(doc, 2),
63 });
64 const tr = state.tr;
65 
66 expect(applyMoveToDetailsContent(tr)).toBe(true);
67 expect(tr.selection.$from.parent.type.name).toBe("paragraph");
68 });
69 
70 it("opens a closed details block before moving into its content", () => {
71 const doc = schema.nodeFromJSON({
72 type: "doc",
73 content: [createDetailsBlockNode({ open: false })],
74 });
75 const state = EditorState.create({
76 schema,
77 doc,
78 selection: TextSelection.create(doc, 2),
79 });
80 const tr = state.tr;
81 
82 expect(applyMoveToDetailsContent(tr)).toBe(true);
83 expect(tr.doc.firstChild?.attrs.open).toBe(true);
84 expect(tr.selection.$from.parent.type.name).toBe("paragraph");
85 });
86});