]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/lexical/list/__tests__/unit/LexicalListNode.test.ts
8c7729dbff10405f0a4df5ffb132b1b84b178bc4
[bookstack] / resources / js / wysiwyg / lexical / list / __tests__ / unit / LexicalListNode.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 import {ParagraphNode, TextNode} from 'lexical';
9 import {initializeUnitTest} from 'lexical/__tests__/utils';
10
11 import {
12   $createListItemNode,
13   $createListNode,
14   $isListItemNode,
15   $isListNode,
16   ListItemNode,
17   ListNode,
18 } from '../..';
19
20 const editorConfig = Object.freeze({
21   namespace: '',
22   theme: {
23     list: {
24       ol: 'my-ol-list-class',
25       olDepth: [
26         'my-ol-list-class-1',
27         'my-ol-list-class-2',
28         'my-ol-list-class-3',
29         'my-ol-list-class-4',
30         'my-ol-list-class-5',
31         'my-ol-list-class-6',
32         'my-ol-list-class-7',
33       ],
34       ul: 'my-ul-list-class',
35       ulDepth: [
36         'my-ul-list-class-1',
37         'my-ul-list-class-2',
38         'my-ul-list-class-3',
39         'my-ul-list-class-4',
40         'my-ul-list-class-5',
41         'my-ul-list-class-6',
42         'my-ul-list-class-7',
43       ],
44     },
45   },
46 });
47
48 describe('LexicalListNode tests', () => {
49   initializeUnitTest((testEnv) => {
50     test('ListNode.constructor', async () => {
51       const {editor} = testEnv;
52
53       await editor.update(() => {
54         const listNode = $createListNode('bullet', 1);
55         expect(listNode.getType()).toBe('list');
56         expect(listNode.getTag()).toBe('ul');
57         expect(listNode.getTextContent()).toBe('');
58       });
59
60       // @ts-expect-error
61       expect(() => $createListNode()).toThrow();
62     });
63
64     test('ListNode.getTag()', async () => {
65       const {editor} = testEnv;
66
67       await editor.update(() => {
68         const ulListNode = $createListNode('bullet', 1);
69         expect(ulListNode.getTag()).toBe('ul');
70         const olListNode = $createListNode('number', 1);
71         expect(olListNode.getTag()).toBe('ol');
72         const checkListNode = $createListNode('check', 1);
73         expect(checkListNode.getTag()).toBe('ul');
74       });
75     });
76
77     test('ListNode.createDOM()', async () => {
78       const {editor} = testEnv;
79
80       await editor.update(() => {
81         const listNode = $createListNode('bullet', 1);
82         expect(listNode.createDOM(editorConfig).outerHTML).toBe(
83           '<ul class="my-ul-list-class my-ul-list-class-1"></ul>',
84         );
85         expect(
86           listNode.createDOM({
87             namespace: '',
88             theme: {
89               list: {},
90             },
91           }).outerHTML,
92         ).toBe('<ul></ul>');
93         expect(
94           listNode.createDOM({
95             namespace: '',
96             theme: {},
97           }).outerHTML,
98         ).toBe('<ul></ul>');
99       });
100     });
101
102     test('ListNode.createDOM() correctly applies classes to a nested ListNode', async () => {
103       const {editor} = testEnv;
104
105       await editor.update(() => {
106         const listNode1 = $createListNode('bullet');
107         const listNode2 = $createListNode('bullet');
108         const listNode3 = $createListNode('bullet');
109         const listNode4 = $createListNode('bullet');
110         const listNode5 = $createListNode('bullet');
111         const listNode6 = $createListNode('bullet');
112         const listNode7 = $createListNode('bullet');
113
114         const listItem1 = $createListItemNode();
115         const listItem2 = $createListItemNode();
116         const listItem3 = $createListItemNode();
117         const listItem4 = $createListItemNode();
118
119         listNode1.append(listItem1);
120         listItem1.append(listNode2);
121         listNode2.append(listItem2);
122         listItem2.append(listNode3);
123         listNode3.append(listItem3);
124         listItem3.append(listNode4);
125         listNode4.append(listItem4);
126         listNode4.append(listNode5);
127         listNode5.append(listNode6);
128         listNode6.append(listNode7);
129
130         expect(listNode1.createDOM(editorConfig).outerHTML).toBe(
131           '<ul class="my-ul-list-class my-ul-list-class-1"></ul>',
132         );
133         expect(
134           listNode1.createDOM({
135             namespace: '',
136             theme: {
137               list: {},
138             },
139           }).outerHTML,
140         ).toBe('<ul></ul>');
141         expect(
142           listNode1.createDOM({
143             namespace: '',
144             theme: {},
145           }).outerHTML,
146         ).toBe('<ul></ul>');
147         expect(listNode2.createDOM(editorConfig).outerHTML).toBe(
148           '<ul class="my-ul-list-class my-ul-list-class-2"></ul>',
149         );
150         expect(listNode3.createDOM(editorConfig).outerHTML).toBe(
151           '<ul class="my-ul-list-class my-ul-list-class-3"></ul>',
152         );
153         expect(listNode4.createDOM(editorConfig).outerHTML).toBe(
154           '<ul class="my-ul-list-class my-ul-list-class-4"></ul>',
155         );
156         expect(listNode5.createDOM(editorConfig).outerHTML).toBe(
157           '<ul class="my-ul-list-class my-ul-list-class-5"></ul>',
158         );
159         expect(listNode6.createDOM(editorConfig).outerHTML).toBe(
160           '<ul class="my-ul-list-class my-ul-list-class-6"></ul>',
161         );
162         expect(listNode7.createDOM(editorConfig).outerHTML).toBe(
163           '<ul class="my-ul-list-class my-ul-list-class-7"></ul>',
164         );
165         expect(
166           listNode5.createDOM({
167             namespace: '',
168             theme: {
169               list: {
170                 ...editorConfig.theme.list,
171                 ulDepth: [
172                   'my-ul-list-class-1',
173                   'my-ul-list-class-2',
174                   'my-ul-list-class-3',
175                 ],
176               },
177             },
178           }).outerHTML,
179         ).toBe('<ul class="my-ul-list-class my-ul-list-class-2"></ul>');
180       });
181     });
182
183     test('ListNode.updateDOM()', async () => {
184       const {editor} = testEnv;
185
186       await editor.update(() => {
187         const listNode = $createListNode('bullet', 1);
188         const domElement = listNode.createDOM(editorConfig);
189
190         expect(domElement.outerHTML).toBe(
191           '<ul class="my-ul-list-class my-ul-list-class-1"></ul>',
192         );
193
194         const newListNode = $createListNode('number', 1);
195         const result = newListNode.updateDOM(
196           listNode,
197           domElement,
198           editorConfig,
199         );
200
201         expect(result).toBe(true);
202         expect(domElement.outerHTML).toBe(
203           '<ul class="my-ul-list-class my-ul-list-class-1"></ul>',
204         );
205       });
206     });
207
208     test('ListNode.append() should properly transform a ListItemNode', async () => {
209       const {editor} = testEnv;
210
211       await editor.update(() => {
212         const listNode = new ListNode('bullet', 1);
213         const listItemNode = new ListItemNode();
214         const textNode = new TextNode('Hello');
215
216         listItemNode.append(textNode);
217         const nodesToAppend = [listItemNode];
218
219         expect(listNode.append(...nodesToAppend)).toBe(listNode);
220         expect(listNode.getFirstChild()).toBe(listItemNode);
221         expect(listNode.getFirstChild()?.getTextContent()).toBe('Hello');
222       });
223     });
224
225     test('ListNode.append() should properly transform a ListNode', async () => {
226       const {editor} = testEnv;
227
228       await editor.update(() => {
229         const listNode = new ListNode('bullet', 1);
230         const nestedListNode = new ListNode('bullet', 1);
231         const listItemNode = new ListItemNode();
232         const textNode = new TextNode('Hello');
233
234         listItemNode.append(textNode);
235         nestedListNode.append(listItemNode);
236
237         const nodesToAppend = [nestedListNode];
238
239         expect(listNode.append(...nodesToAppend)).toBe(listNode);
240         expect($isListItemNode(listNode.getFirstChild())).toBe(true);
241         expect(listNode.getFirstChild<ListItemNode>()!.getFirstChild()).toBe(
242           nestedListNode,
243         );
244       });
245     });
246
247     test('ListNode.append() should properly transform a ParagraphNode', async () => {
248       const {editor} = testEnv;
249
250       await editor.update(() => {
251         const listNode = new ListNode('bullet', 1);
252         const paragraph = new ParagraphNode();
253         const textNode = new TextNode('Hello');
254         paragraph.append(textNode);
255         const nodesToAppend = [paragraph];
256
257         expect(listNode.append(...nodesToAppend)).toBe(listNode);
258         expect($isListItemNode(listNode.getFirstChild())).toBe(true);
259         expect(listNode.getFirstChild()?.getTextContent()).toBe('Hello');
260       });
261     });
262
263     test('$createListNode()', async () => {
264       const {editor} = testEnv;
265
266       await editor.update(() => {
267         const listNode = $createListNode('bullet', 1);
268         const createdListNode = $createListNode('bullet');
269
270         expect(listNode.__type).toEqual(createdListNode.__type);
271         expect(listNode.__parent).toEqual(createdListNode.__parent);
272         expect(listNode.__tag).toEqual(createdListNode.__tag);
273         expect(listNode.__key).not.toEqual(createdListNode.__key);
274       });
275     });
276
277     test('$isListNode()', async () => {
278       const {editor} = testEnv;
279
280       await editor.update(() => {
281         const listNode = $createListNode('bullet', 1);
282
283         expect($isListNode(listNode)).toBe(true);
284       });
285     });
286
287     test('$createListNode() with tag name (backward compatibility)', async () => {
288       const {editor} = testEnv;
289
290       await editor.update(() => {
291         const numberList = $createListNode('number', 1);
292         const bulletList = $createListNode('bullet', 1);
293         expect(numberList.__listType).toBe('number');
294         expect(bulletList.__listType).toBe('bullet');
295       });
296     });
297   });
298 });