Skip to content
File

Blob: tests/client/components/editor/controllers/callout.test.ts

typescript84 lines
1import { describe, expect, it } from "vitest";
2import { getSchema } from "@tiptap/core";
3import { StarterKit } from "@tiptap/starter-kit";
4import { createCalloutNode, type CalloutBlockAttrs } from "@/client/components/editor/controllers/callout";
5import { CalloutExtension } from "@/client/components/editor/extensions/callout";
6import {
7 CALLOUT_KINDS,
8 DEFAULT_CALLOUT_KIND,
9 normalizeCalloutKind,
10} from "@/client/components/editor/extensions/callout/kinds";
11 
12const schema = getSchema([StarterKit.configure({ undoRedo: false }), CalloutExtension]);
13 
14describe("callout block helpers", () => {
15 it("defaults to info kind with a single empty paragraph", () => {
16 expect(createCalloutNode()).toEqual({
17 type: "callout",
18 attrs: { kind: "info" },
19 content: [{ type: "paragraph" }],
20 });
21 });
22 
23 it("honors an explicit supported kind", () => {
24 expect(createCalloutNode({ kind: "warning" })).toEqual({
25 type: "callout",
26 attrs: { kind: "warning" },
27 content: [{ type: "paragraph" }],
28 });
29 });
30 
31 it("falls back to the default kind when given an unknown kind", () => {
32 const attrs = { kind: "bogus" } as unknown as CalloutBlockAttrs;
33 expect(createCalloutNode(attrs)).toEqual({
34 type: "callout",
35 attrs: { kind: DEFAULT_CALLOUT_KIND },
36 content: [{ type: "paragraph" }],
37 });
38 });
39 
40 it("exposes every supported kind through normalizeCalloutKind", () => {
41 for (const kind of CALLOUT_KINDS) {
42 expect(normalizeCalloutKind(kind)).toBe(kind);
43 }
44 expect(normalizeCalloutKind(null)).toBe(DEFAULT_CALLOUT_KIND);
45 expect(normalizeCalloutKind(undefined)).toBe(DEFAULT_CALLOUT_KIND);
46 expect(normalizeCalloutKind("nope")).toBe(DEFAULT_CALLOUT_KIND);
47 expect(normalizeCalloutKind(42)).toBe(DEFAULT_CALLOUT_KIND);
48 });
49 
50 it("round-trips through the editor schema without losing content", () => {
51 const doc = schema.nodeFromJSON({
52 type: "doc",
53 content: [
54 createCalloutNode({ kind: "tip" }),
55 {
56 type: "callout",
57 attrs: { kind: "warning" },
58 content: [
59 { type: "paragraph", content: [{ type: "text", text: "Hello inside a callout" }] },
60 {
61 type: "bulletList",
62 content: [
63 {
64 type: "listItem",
65 content: [{ type: "paragraph", content: [{ type: "text", text: "nested list item" }] }],
66 },
67 ],
68 },
69 ],
70 },
71 ],
72 });
73 
74 expect(doc.childCount).toBe(2);
75 expect(doc.firstChild?.type.name).toBe("callout");
76 expect(doc.firstChild?.attrs.kind).toBe("tip");
77 const second = doc.child(1);
78 expect(second.attrs.kind).toBe("warning");
79 expect(second.childCount).toBe(2);
80 expect(second.textContent).toContain("Hello inside a callout");
81 expect(second.textContent).toContain("nested list item");
82 });
83});