resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalNodeHelpers.test.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {
$createParagraphNode,
$createTextNode,
$getNodeByKey,
$getRoot,
$isElementNode,
LexicalEditor,
NodeKey,
} from 'lexical';
import {
$createTestElementNode,
initializeUnitTest,
invariant,
} from 'lexical/__tests__/utils';
import {$dfs} from '../..';
describe('LexicalNodeHelpers tests', () => {
initializeUnitTest((testEnv) => {
/**
* R
* P1 P2
* B1 B2 T4 T5 B3
* T1 T2 T3 T6
*
* DFS: R, P1, B1, T1, B2, T2, T3, P2, T4, T5, B3, T6
*/
test('DFS node order', async () => {
const editor: LexicalEditor = testEnv.editor;
let expectedKeys: Array<{
depth: number;
node: NodeKey;
}> = [];
await editor.update(() => {
const root = $getRoot();
const paragraph1 = $createParagraphNode();
const paragraph2 = $createParagraphNode();
const block1 = $createTestElementNode();
const block2 = $createTestElementNode();
const block3 = $createTestElementNode();
const text1 = $createTextNode('text1');
const text2 = $createTextNode('text2');
const text3 = $createTextNode('text3');
const text4 = $createTextNode('text4');
const text5 = $createTextNode('text5');
const text6 = $createTextNode('text6');
root.append(paragraph1, paragraph2);
paragraph1.append(block1, block2);
paragraph2.append(text4, text5);
text5.toggleFormat('bold'); // Prevent from merging with text 4
paragraph2.append(block3);
block1.append(text1);
block2.append(text2, text3);
text3.toggleFormat('bold'); // Prevent from merging with text2
block3.append(text6);
expectedKeys = [
{
depth: 0,
node: root.getKey(),
},
{
depth: 1,
node: paragraph1.getKey(),
},
{
depth: 2,
node: block1.getKey(),
},
{
depth: 3,
node: text1.getKey(),
},
{
depth: 2,
node: block2.getKey(),
},
{
depth: 3,
node: text2.getKey(),
},
{
depth: 3,
node: text3.getKey(),
},
{
depth: 1,
node: paragraph2.getKey(),
},
{
depth: 2,
node: text4.getKey(),
},
{
depth: 2,
node: text5.getKey(),
},
{
depth: 2,
node: block3.getKey(),
},
{
depth: 3,
node: text6.getKey(),
},
];
});
editor.getEditorState().read(() => {
const expectedNodes = expectedKeys.map(({depth, node: nodeKey}) => ({
depth,
node: $getNodeByKey(nodeKey)!.getLatest(),
}));
const first = expectedNodes[0];
const second = expectedNodes[1];
const last = expectedNodes[expectedNodes.length - 1];
const secondToLast = expectedNodes[expectedNodes.length - 2];
expect($dfs(first.node, last.node)).toEqual(expectedNodes);
expect($dfs(second.node, secondToLast.node)).toEqual(
expectedNodes.slice(1, expectedNodes.length - 1),
);
expect($dfs()).toEqual(expectedNodes);
expect($dfs($getRoot())).toEqual(expectedNodes);
});
});
test('DFS triggers getLatest()', async () => {
const editor: LexicalEditor = testEnv.editor;
let rootKey: string;
let paragraphKey: string;
let block1Key: string;
let block2Key: string;
await editor.update(() => {
const root = $getRoot();
const paragraph = $createParagraphNode();
const block1 = $createTestElementNode();
const block2 = $createTestElementNode();
rootKey = root.getKey();
paragraphKey = paragraph.getKey();
block1Key = block1.getKey();
block2Key = block2.getKey();
root.append(paragraph);
paragraph.append(block1, block2);
});
await editor.update(() => {
const root = $getNodeByKey(rootKey);
const paragraph = $getNodeByKey(paragraphKey);
const block1 = $getNodeByKey(block1Key);
const block2 = $getNodeByKey(block2Key);
const block3 = $createTestElementNode();
invariant($isElementNode(block1));
block1.append(block3);
expect($dfs(root!)).toEqual([
{
depth: 0,
node: root!.getLatest(),
},
{
depth: 1,
node: paragraph!.getLatest(),
},
{
depth: 2,
node: block1.getLatest(),
},
{
depth: 3,
node: block3.getLatest(),
},
{
depth: 2,
node: block2!.getLatest(),
},
]);
});
});
test('DFS of empty ParagraphNode returns only itself', async () => {
const editor: LexicalEditor = testEnv.editor;
let paragraphKey: string;
await editor.update(() => {
const root = $getRoot();
const paragraph = $createParagraphNode();
const paragraph2 = $createParagraphNode();
const text = $createTextNode('test');
paragraphKey = paragraph.getKey();
paragraph2.append(text);
root.append(paragraph, paragraph2);
});
await editor.update(() => {
const paragraph = $getNodeByKey(paragraphKey)!;
expect($dfs(paragraph ?? undefined)).toEqual([
{
depth: 1,
node: paragraph?.getLatest(),
},
]);
});
});
});
});