import { Plugin } from "@html_editor/plugin"; import { MAIN_PLUGINS } from "@html_editor/plugin_sets"; import { closestElement } from "@html_editor/utils/dom_traversal"; import { expect, test } from "@odoo/hoot"; import { setupEditor } from "./_helpers/editor"; import { insertText } from "./_helpers/user_actions"; import { getContent } from "./_helpers/selection"; test("can get content of an Editor", async () => { const { el, editor } = await setupEditor("

hel[lo] world

", {}); expect(el.innerHTML).toBe(`

hello world

`); expect(editor.getContent()).toBe(`

hello world

`); }); test("can get content of an empty paragraph", async () => { const { el, editor } = await setupEditor("

[]

", {}); expect(el.innerHTML).toBe( `

` ); expect(editor.getContent()).toBe(`

`); }); test("is notified when content is changed", async () => { let n = 0; const { editor } = await setupEditor("

hello[] world

", { config: { onChange: () => n++ }, }); expect(n).toBe(0); await insertText(editor, "a"); expect(editor.getContent()).toBe(`

helloa world

`); expect(n).toBe(1); }); test("plugin destruction is reverse of instantiation order", async () => { function makeTestPlugin(id, dependencies = []) { return class TestPlugin extends Plugin { static id = id; static dependencies = dependencies; setup() { expect.step(`setup: ${id}`); } destroy() { expect.step(`destroy: ${id}`); } }; } const Plugins = [...MAIN_PLUGINS, makeTestPlugin("first"), makeTestPlugin("second", ["first"])]; const { editor } = await setupEditor(`

[]

`, { config: { Plugins } }); expect.verifySteps(["setup: first", "setup: second"]); editor.destroy(); expect.verifySteps(["destroy: second", "destroy: first"]); }); test("Remove odoo-editor-editable class after every plugin is destroyed", async () => { class TestPlugin extends Plugin { static id = "test"; destroy() { const p = this.editable.querySelector("p"); if (closestElement(p, "div")) { expect.step("operation"); } } } const Plugins = [...MAIN_PLUGINS, TestPlugin]; const { editor } = await setupEditor(`

a

`, { config: { Plugins } }); editor.destroy(); expect.verifySteps(["operation"]); }); test("clean_for_save_listeners is done last", async () => { // This test uses custom elements tag `c-div` to make sure they won't fall into // a case where they won't be merged anyway. // Without the proper fix, this test fails with sibling elements `c-div` merged together class TestPlugin extends Plugin { static id = "test"; resources = { clean_for_save_handlers: ({ root }) => { for (const el of root.querySelectorAll("c-div")) { el.removeAttribute("class"); } }, }; setup() { for (const el of this.editable.querySelectorAll("c-div")) { el.classList.add("oe_unbreakable"); } } } const Plugins = [...MAIN_PLUGINS, TestPlugin]; const { editor } = await setupEditor(`
ab
`, { config: { Plugins }, }); const el = editor.getElContent(); expect(getContent(el)).toBe(`
ab
`); }); test("Convert self closing a elements to opening/closing tags", async () => { const { el, editor } = await setupEditor(` `); expect(el.innerHTML.trim().replace(/\s+/g, " ")).toBe( `` ); expect(editor.getContent().trim().replace(/\s+/g, " ")).toBe( '' ); }); test("Convert self closing t elements to opening/closing tags", async () => { const { el, editor } = await setupEditor(`
`); expect(el.innerHTML.trim().replace(/\s+/g, " ")).toBe( `
` ); expect(editor.getContent().trim().replace(/\s+/g, " ")).toBe( '
' ); });