2 * Copyright (c) Meta Platforms, Inc. and affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
13 } from '@lexical/rich-text';
21 import {initializeUnitTest} from 'lexical/src/__tests__/utils';
23 const editorConfig = Object.freeze({
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('');
47 expect(() => new HeadingNode('h1')).toThrow();
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>',
58 headingNode.createDOM({
66 headingNode.createDOM({
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>');
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);
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>',
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());
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>',
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);
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>',
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());
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>',
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();
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>',
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());
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>',
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);
170 test('$isHeadingNode()', async () => {
171 const {editor} = testEnv;
172 await editor.update(() => {
173 const headingNode = new HeadingNode('h1');
174 expect($isHeadingNode(headingNode)).toBe(true);
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);
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>`,
192 await editor.update(() => {
193 const result = headingNode.insertNewAfter();
194 expect(result).toBeInstanceOf(ParagraphNode);
195 expect(result.getDirection()).toEqual(headingNode.getDirection());
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>`,