import { describe, expect, test } from "@odoo/hoot"; import { setupEditor } from "../_helpers/editor"; import { cleanTextNode, fillEmpty, splitTextNode, wrapInlinesInBlocks, } from "@html_editor/utils/dom"; import { getContent } from "../_helpers/selection"; import { parseHTML } from "@html_editor/utils/html"; import { unformat } from "../_helpers/format"; describe("splitAroundUntil", () => { test("should split a slice of text from its inline ancestry (1)", async () => { const { editor, el } = await setupEditor("
abcdefg
"); const [p] = el.childNodes; const cde = p.childNodes[1].childNodes[1].firstChild; // We want to test with "cde" being three separate text nodes. splitTextNode(cde, 2); const cd = cde.previousSibling; splitTextNode(cd, 1); const d = cd; const result = editor.shared.split.splitAroundUntil(d, p.childNodes[1]); expect(result.tagName === "FONT").toBe(true); expect(p.outerHTML).toBe( "abcdefg
" ); }); test("should split a slice of text from its inline ancestry (2)", async () => { const { editor, el } = await setupEditor("abcdefghi
"); const [p] = el.childNodes; const cdefg = p.childNodes[1].childNodes[1].firstChild; // We want to test with "cdefg" being five separate text nodes. splitTextNode(cdefg, 4); const cdef = cdefg.previousSibling; splitTextNode(cdef, 3); const cde = cdef.previousSibling; splitTextNode(cde, 2); const cd = cde.previousSibling; splitTextNode(cd, 1); const d = cd; const result = editor.shared.split.splitAroundUntil( [d, d.nextSibling.nextSibling], p.childNodes[1] ); expect(result.tagName === "FONT").toBe(true); expect(p.outerHTML).toBe( "abcdefghi
" ); }); test("should split from a textNode that has no siblings", async () => { const { editor, el } = await setupEditor("abcdefg
"); const [p] = el.childNodes; const font = p.querySelector("font"); const cde = p.querySelector("span").firstChild; const result = editor.shared.split.splitAroundUntil(cde, font); expect(result.tagName === "FONT" && result !== font).toBe(true); expect(p.outerHTML).toBe( "abcdefg
" ); }); test("should not do anything (nothing to split)", async () => { const { editor, el } = await setupEditor("abcde
"); const [p] = el.childNodes; const bcd = p.querySelector("span").firstChild; const result = editor.shared.split.splitAroundUntil(bcd, p.childNodes[1]); expect(result === p.childNodes[1]).toBe(true); expect(p.outerHTML).toBe("abcde
"); }); }); describe("cleanTextNode", () => { test("should remove ZWS before cursor and preserve it", async () => { const { editor, el } = await setupEditor("\u200B[]text
"); const cursors = editor.shared.selection.preserveSelection(); cleanTextNode(el.querySelector("p").firstChild, "\u200B", cursors); cursors.restore(); expect(getContent(el)).toBe("[]text
"); }); test("should remove ZWS before cursor and preserve it (2)", async () => { const { editor, el } = await setupEditor("\u200Bt[]ext
"); const cursors = editor.shared.selection.preserveSelection(); cleanTextNode(el.querySelector("p").firstChild, "\u200B", cursors); cursors.restore(); expect(getContent(el)).toBe("t[]ext
"); }); test("should remove ZWS after cursor and preserve it", async () => { const { editor, el } = await setupEditor("text[]\u200B
"); const cursors = editor.shared.selection.preserveSelection(); cleanTextNode(el.querySelector("p").firstChild, "\u200B", cursors); cursors.restore(); expect(getContent(el)).toBe("text[]
"); }); test("should remove ZWS after cursor and preserve it (2)", async () => { const { editor, el } = await setupEditor("t[]ext\u200B
"); const cursors = editor.shared.selection.preserveSelection(); cleanTextNode(el.querySelector("p").firstChild, "\u200B", cursors); cursors.restore(); expect(getContent(el)).toBe("t[]ext
"); }); test("should remove multiple ZWS preserving cursor", async () => { const { editor, el } = await setupEditor("\u200Bt\u200Be[]\u200Bxt\u200B
"); const cursors = editor.shared.selection.preserveSelection(); cleanTextNode(el.querySelector("p").firstChild, "\u200B", cursors); cursors.restore(); expect(getContent(el)).toBe("te[]xt
"); }); test("should remove multiple ZWNBSP preserving cursor", async () => { const { editor, el } = await setupEditor("\uFEFFt\uFEFFe[]\uFEFFxt\uFEFF
"); const cursors = editor.shared.selection.preserveSelection(); cleanTextNode(el.querySelector("p").firstChild, "\uFEFF", cursors); cursors.restore(); expect(getContent(el)).toBe("te[]xt
"); }); }); describe("wrapInlinesInBlocks", () => { test("should wrap text node in P", async () => { const div = document.createElement("div"); div.innerHTML = "text"; wrapInlinesInBlocks(div); expect(div.innerHTML).toBe("text
"); }); test("should wrap inline element in P", async () => { const div = document.createElement("div"); div.innerHTML = "text"; wrapInlinesInBlocks(div); expect(div.innerHTML).toBe("text
"); }); test("should not do anything to block element", async () => { const div = document.createElement("div"); div.innerHTML = "text
"; wrapInlinesInBlocks(div); expect(div.innerHTML).toBe("text
"); }); test("should wrap inlines in P", async () => { const div = document.createElement("div"); div.innerHTML = "textnodeinlinep
"; wrapInlinesInBlocks(div); expect(div.innerHTML).toBe("textnodeinline
p
"); }); test("should wrap inlines in P (2)", async () => { const div = document.createElement("div"); div.innerHTML = "inlinep
textnode"; wrapInlinesInBlocks(div); expect(div.innerHTML).toBe("inline
p
textnode
"); }); test("should turn a BR into a paragraph break", async () => { const div = document.createElement("div"); div.innerHTML = "abcabc
def
"); }); test("should remove a BR that has no effect", async () => { const div = document.createElement("div"); div.innerHTML = "abcabc
def
"); }); test("empty lines should become empty paragraphs", async () => { const div = document.createElement("div"); div.innerHTML = "abcabc
def
"); }); test("empty lines should become empty paragraphs (2)", async () => { const div = document.createElement("div"); div.innerHTML = "abc
"); }); test("mix: handle blocks, inlines and BRs", async () => { const div = document.createElement("div"); div.innerHTML = "aa
b
d
text
span
[]text
span
`) ); }); }); describe("fillEmpty", () => { test("should not add fill a shrunk protected block, nor add a ZWS to it", async () => { const { el } = await setupEditor(''); expect(el.innerHTML).toBe(''); const div = el.firstChild; fillEmpty(div); expect(el.innerHTML).toBe(''); }); });