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.
10 import type {RangeSelection} from 'lexical';
12 import {createHeadlessEditor} from '@lexical/headless';
13 import {$generateHtmlFromNodes, $generateNodesFromDOM} from '@lexical/html';
14 import {LinkNode} from '@lexical/link';
15 import {ListItemNode, ListNode} from '@lexical/list';
18 $createRangeSelection,
22 import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
23 import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
25 describe('HTML', () => {
29 initializeEditorState: () => void;
32 const HTML_SERIALIZE: Input = [
35 initializeEditorState: () => {
36 $getRoot().append($createParagraphNode());
38 name: 'Empty editor state',
41 for (const {name, html, initializeEditorState} of HTML_SERIALIZE) {
42 test(`[Lexical -> HTML]: ${name}`, () => {
43 const editor = createHeadlessEditor({
53 editor.update(initializeEditorState, {
58 editor.getEditorState().read(() => $generateHtmlFromNodes(editor)),
63 test(`[Lexical -> HTML]: Use provided selection`, () => {
64 const editor = createHeadlessEditor({
74 let selection: RangeSelection | null = null;
78 const root = $getRoot();
79 const p1 = $createParagraphNode();
80 const text1 = $createTextNode('Hello');
82 const p2 = $createParagraphNode();
83 const text2 = $createTextNode('World');
85 root.append(p1).append(p2);
88 // -- TextNode "Hello"
90 // -- TextNode "World"
91 p1.select(0, text1.getTextContentSize());
92 selection = $createRangeSelection();
93 selection.setTextNodeRange(text2, 0, text2, text2.getTextContentSize());
102 editor.update(() => {
103 html = $generateHtmlFromNodes(editor, selection);
106 expect(html).toBe('World');
109 test(`[Lexical -> HTML]: Default selection (undefined) should serialize entire editor state`, () => {
110 const editor = createHeadlessEditor({
122 const root = $getRoot();
123 const p1 = $createParagraphNode();
124 const text1 = $createTextNode('Hello');
126 const p2 = $createParagraphNode();
127 const text2 = $createTextNode('World');
129 root.append(p1).append(p2);
132 // -- TextNode "Hello"
134 // -- TextNode "World"
135 p1.select(0, text1.getTextContentSize());
144 editor.update(() => {
145 html = $generateHtmlFromNodes(editor);
149 '<p>Hello</p><p>World</p>',
153 test(`If alignment is set on the paragraph, don't overwrite from parent empty format`, () => {
154 const editor = createHeadlessEditor();
155 const parser = new DOMParser();
156 const rightAlignedParagraphInDiv =
157 '<div><p style="text-align: center;">Hello world!</p></div>';
161 const root = $getRoot();
162 const dom = parser.parseFromString(
163 rightAlignedParagraphInDiv,
166 const nodes = $generateNodesFromDOM(editor, dom);
167 root.append(...nodes);
174 editor.update(() => {
175 html = $generateHtmlFromNodes(editor);
179 '<p style="text-align: center;">Hello world!</p>',
183 test(`If alignment is set on the paragraph, it should take precedence over its parent block alignment`, () => {
184 const editor = createHeadlessEditor();
185 const parser = new DOMParser();
186 const rightAlignedParagraphInDiv =
187 '<div style="text-align: right;"><p style="text-align: center;">Hello world!</p></div>';
191 const root = $getRoot();
192 const dom = parser.parseFromString(
193 rightAlignedParagraphInDiv,
196 const nodes = $generateNodesFromDOM(editor, dom);
197 root.append(...nodes);
204 editor.update(() => {
205 html = $generateHtmlFromNodes(editor);
209 '<p style="text-align: center;">Hello world!</p>',