]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/lexical/core/__tests__/unit/LexicalListPlugin.test.tsx
a2968c2592bda25cd3724b4ca4f7043d5fe6f166
[bookstack] / resources / js / wysiwyg / lexical / core / __tests__ / unit / LexicalListPlugin.test.tsx
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 {ListItemNode, ListNode} from '@lexical/list';
9 import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
10 import {ContentEditable} from '@lexical/react/LexicalContentEditable';
11 import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
12 import {ListPlugin} from '@lexical/react/LexicalListPlugin';
13 import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
14 import {
15   INDENT_CONTENT_COMMAND,
16   LexicalEditor,
17   OUTDENT_CONTENT_COMMAND,
18 } from 'lexical';
19 import {
20   expectHtmlToBeEqual,
21   html,
22   TestComposer,
23 } from 'lexical/src/__tests__/utils';
24 import {createRoot, Root} from 'react-dom/client';
25 import * as ReactTestUtils from 'lexical/shared/react-test-utils';
26
27 import {
28   INSERT_UNORDERED_LIST_COMMAND,
29   REMOVE_LIST_COMMAND,
30 } from '../../../../lexical-list/src/index';
31
32 describe('@lexical/list tests', () => {
33   let container: HTMLDivElement;
34   let reactRoot: Root;
35
36   beforeEach(() => {
37     container = document.createElement('div');
38     reactRoot = createRoot(container);
39     document.body.appendChild(container);
40   });
41
42   afterEach(() => {
43     container.remove();
44     // @ts-ignore
45     container = null;
46
47     jest.restoreAllMocks();
48   });
49
50   // Shared instance across tests
51   let editor: LexicalEditor;
52
53   function Test(): JSX.Element {
54     function TestPlugin() {
55       // Plugin used just to get our hands on the Editor object
56       [editor] = useLexicalComposerContext();
57       return null;
58     }
59
60     return (
61       <TestComposer config={{nodes: [ListNode, ListItemNode], theme: {}}}>
62         <RichTextPlugin
63           contentEditable={<ContentEditable />}
64           placeholder={
65             <div className="editor-placeholder">Enter some text...</div>
66           }
67           ErrorBoundary={LexicalErrorBoundary}
68         />
69         <TestPlugin />
70         <ListPlugin />
71       </TestComposer>
72     );
73   }
74
75   test('Toggle an empty list on/off', async () => {
76     ReactTestUtils.act(() => {
77       reactRoot.render(<Test key="MegaSeeds, Morty!" />);
78     });
79
80     await ReactTestUtils.act(async () => {
81       await editor.update(() => {
82         editor.focus();
83         editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
84       });
85     });
86
87     expectHtmlToBeEqual(
88       container.innerHTML,
89       html`
90         <div
91           contenteditable="true"
92           role="textbox"
93           spellcheck="true"
94           style="user-select: text; white-space: pre-wrap; word-break: break-word;"
95           data-lexical-editor="true">
96           <ul>
97             <li value="1">
98               <br />
99             </li>
100           </ul>
101         </div>
102       `,
103     );
104
105     await ReactTestUtils.act(async () => {
106       await editor.update(() => {
107         editor.focus();
108         editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
109       });
110     });
111
112     expectHtmlToBeEqual(
113       container.innerHTML,
114       html`
115         <div
116           contenteditable="true"
117           role="textbox"
118           spellcheck="true"
119           style="user-select: text; white-space: pre-wrap; word-break: break-word;"
120           data-lexical-editor="true">
121           <p>
122             <br />
123           </p>
124         </div>
125         <div class="editor-placeholder">Enter some text...</div>
126       `,
127     );
128   });
129
130   test('Can create a list and indent/outdent it', async () => {
131     ReactTestUtils.act(() => {
132       reactRoot.render(<Test key="MegaSeeds, Morty!" />);
133     });
134
135     await ReactTestUtils.act(async () => {
136       await editor.update(() => {
137         editor.focus();
138         editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
139       });
140     });
141
142     expectHtmlToBeEqual(
143       container.innerHTML,
144       html`
145         <div
146           contenteditable="true"
147           role="textbox"
148           spellcheck="true"
149           style="user-select: text; white-space: pre-wrap; word-break: break-word;"
150           data-lexical-editor="true">
151           <ul>
152             <li value="1">
153               <br />
154             </li>
155           </ul>
156         </div>
157       `,
158     );
159
160     await ReactTestUtils.act(async () => {
161       await editor.update(() => {
162         editor.focus();
163         editor.dispatchCommand(INDENT_CONTENT_COMMAND, undefined);
164       });
165     });
166
167     expectHtmlToBeEqual(
168       container.innerHTML,
169       html`
170         <div
171           contenteditable="true"
172           role="textbox"
173           spellcheck="true"
174           style="user-select: text; white-space: pre-wrap; word-break: break-word;"
175           data-lexical-editor="true">
176           <ul>
177             <li value="1">
178               <ul>
179                 <li value="1"><br /></li>
180               </ul>
181             </li>
182           </ul>
183         </div>
184       `,
185     );
186
187     await ReactTestUtils.act(async () => {
188       await editor.update(() => {
189         editor.focus();
190         editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, undefined);
191       });
192     });
193
194     expectHtmlToBeEqual(
195       container.innerHTML,
196       html`
197         <div
198           contenteditable="true"
199           role="textbox"
200           spellcheck="true"
201           style="user-select: text; white-space: pre-wrap; word-break: break-word;"
202           data-lexical-editor="true">
203           <ul>
204             <li value="1">
205               <br />
206             </li>
207           </ul>
208         </div>
209       `,
210     );
211   });
212 });