]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/lexical/rich-text/__tests__/unit/LexicalHeadingNode.test.ts
057999ba031cf97194171147de709edf7d0a19a0
[bookstack] / resources / js / wysiwyg / lexical / rich-text / __tests__ / unit / LexicalHeadingNode.test.ts
1 /**
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  *
7  */
8
9 import {
10   $createHeadingNode,
11   $isHeadingNode,
12   HeadingNode,
13 } from '@lexical/rich-text';
14 import {
15   $createTextNode,
16   $getRoot,
17   $getSelection,
18   ParagraphNode,
19   RangeSelection,
20 } from 'lexical';
21 import {initializeUnitTest} from 'lexical/src/__tests__/utils';
22
23 const editorConfig = Object.freeze({
24   namespace: '',
25   theme: {
26     heading: {
27       h1: 'my-h1-class',
28       h2: 'my-h2-class',
29       h3: 'my-h3-class',
30       h4: 'my-h4-class',
31       h5: 'my-h5-class',
32       h6: 'my-h6-class',
33     },
34   },
35 });
36
37 describe('LexicalHeadingNode tests', () => {
38   initializeUnitTest((testEnv) => {
39     test('HeadingNode.constructor', async () => {
40       const {editor} = testEnv;
41       await editor.update(() => {
42         const headingNode = new HeadingNode('h1');
43         expect(headingNode.getType()).toBe('heading');
44         expect(headingNode.getTag()).toBe('h1');
45         expect(headingNode.getTextContent()).toBe('');
46       });
47       expect(() => new HeadingNode('h1')).toThrow();
48     });
49
50     test('HeadingNode.createDOM()', async () => {
51       const {editor} = testEnv;
52       await editor.update(() => {
53         const headingNode = new HeadingNode('h1');
54         expect(headingNode.createDOM(editorConfig).outerHTML).toBe(
55           '<h1 class="my-h1-class"></h1>',
56         );
57         expect(
58           headingNode.createDOM({
59             namespace: '',
60             theme: {
61               heading: {},
62             },
63           }).outerHTML,
64         ).toBe('<h1></h1>');
65         expect(
66           headingNode.createDOM({
67             namespace: '',
68             theme: {},
69           }).outerHTML,
70         ).toBe('<h1></h1>');
71       });
72     });
73
74     test('HeadingNode.updateDOM()', async () => {
75       const {editor} = testEnv;
76       await editor.update(() => {
77         const headingNode = new HeadingNode('h1');
78         const domElement = headingNode.createDOM(editorConfig);
79         expect(domElement.outerHTML).toBe('<h1 class="my-h1-class"></h1>');
80         const newHeadingNode = new HeadingNode('h2');
81         const result = newHeadingNode.updateDOM(headingNode, domElement);
82         expect(result).toBe(false);
83         expect(domElement.outerHTML).toBe('<h1 class="my-h1-class"></h1>');
84       });
85     });
86
87     test('HeadingNode.insertNewAfter() empty', async () => {
88       const {editor} = testEnv;
89       let headingNode: HeadingNode;
90       await editor.update(() => {
91         const root = $getRoot();
92         headingNode = new HeadingNode('h1');
93         root.append(headingNode);
94       });
95       expect(testEnv.outerHTML).toBe(
96         '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h1><br></h1></div>',
97       );
98       await editor.update(() => {
99         const selection = $getSelection() as RangeSelection;
100         const result = headingNode.insertNewAfter(selection);
101         expect(result).toBeInstanceOf(ParagraphNode);
102         expect(result.getDirection()).toEqual(headingNode.getDirection());
103       });
104       expect(testEnv.outerHTML).toBe(
105         '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h1><br></h1><p><br></p></div>',
106       );
107     });
108
109     test('HeadingNode.insertNewAfter() middle', async () => {
110       const {editor} = testEnv;
111       let headingNode: HeadingNode;
112       await editor.update(() => {
113         const root = $getRoot();
114         headingNode = new HeadingNode('h1');
115         const headingTextNode = $createTextNode('hello world');
116         root.append(headingNode.append(headingTextNode));
117         headingTextNode.select(5, 5);
118       });
119       expect(testEnv.outerHTML).toBe(
120         '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h1 dir="ltr"><span data-lexical-text="true">hello world</span></h1></div>',
121       );
122       await editor.update(() => {
123         const selection = $getSelection() as RangeSelection;
124         const result = headingNode.insertNewAfter(selection);
125         expect(result).toBeInstanceOf(HeadingNode);
126         expect(result.getDirection()).toEqual(headingNode.getDirection());
127       });
128       expect(testEnv.outerHTML).toBe(
129         '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h1 dir="ltr"><span data-lexical-text="true">hello world</span></h1><h1><br></h1></div>',
130       );
131     });
132
133     test('HeadingNode.insertNewAfter() end', async () => {
134       const {editor} = testEnv;
135       let headingNode: HeadingNode;
136       await editor.update(() => {
137         const root = $getRoot();
138         headingNode = new HeadingNode('h1');
139         const headingTextNode1 = $createTextNode('hello');
140         const headingTextNode2 = $createTextNode(' world');
141         headingTextNode2.setFormat('bold');
142         root.append(headingNode.append(headingTextNode1, headingTextNode2));
143         headingTextNode2.selectEnd();
144       });
145       expect(testEnv.outerHTML).toBe(
146         '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h1 dir="ltr"><span data-lexical-text="true">hello</span><strong data-lexical-text="true"> world</strong></h1></div>',
147       );
148       await editor.update(() => {
149         const selection = $getSelection() as RangeSelection;
150         const result = headingNode.insertNewAfter(selection);
151         expect(result).toBeInstanceOf(ParagraphNode);
152         expect(result.getDirection()).toEqual(headingNode.getDirection());
153       });
154       expect(testEnv.outerHTML).toBe(
155         '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h1 dir="ltr"><span data-lexical-text="true">hello</span><strong data-lexical-text="true"> world</strong></h1><p><br></p></div>',
156       );
157     });
158
159     test('$createHeadingNode()', async () => {
160       const {editor} = testEnv;
161       await editor.update(() => {
162         const headingNode = new HeadingNode('h1');
163         const createdHeadingNode = $createHeadingNode('h1');
164         expect(headingNode.__type).toEqual(createdHeadingNode.__type);
165         expect(headingNode.__parent).toEqual(createdHeadingNode.__parent);
166         expect(headingNode.__key).not.toEqual(createdHeadingNode.__key);
167       });
168     });
169
170     test('$isHeadingNode()', async () => {
171       const {editor} = testEnv;
172       await editor.update(() => {
173         const headingNode = new HeadingNode('h1');
174         expect($isHeadingNode(headingNode)).toBe(true);
175       });
176     });
177
178     test('creates a h2 with text and can insert a new paragraph after', async () => {
179       const {editor} = testEnv;
180       let headingNode: HeadingNode;
181       const text = 'hello world';
182       await editor.update(() => {
183         const root = $getRoot();
184         headingNode = new HeadingNode('h2');
185         root.append(headingNode);
186         const textNode = $createTextNode(text);
187         headingNode.append(textNode);
188       });
189       expect(testEnv.outerHTML).toBe(
190         `<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h2 dir="ltr"><span data-lexical-text="true">${text}</span></h2></div>`,
191       );
192       await editor.update(() => {
193         const result = headingNode.insertNewAfter();
194         expect(result).toBeInstanceOf(ParagraphNode);
195         expect(result.getDirection()).toEqual(headingNode.getDirection());
196       });
197       expect(testEnv.outerHTML).toBe(
198         `<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><h2 dir="ltr"><span data-lexical-text="true">${text}</span></h2><p><br></p></div>`,
199       );
200     });
201   });
202 });