mirror of
https://github.com/bringout/oca-ocb-web.git
synced 2026-04-19 04:12:01 +02:00
replace stale web_editor with html_editor and html_builder for 19.0
web_editor was removed in Odoo 19.0 and replaced by html_editor
and html_builder. The old web_editor was incorrectly included in
the 19.0 vanilla import.
🤖 assisted by claude
This commit is contained in:
parent
4b94f0abc5
commit
f866779561
1513 changed files with 396049 additions and 358525 deletions
|
|
@ -0,0 +1,279 @@
|
|||
import { setupHTMLBuilder } from "@html_builder/../tests/helpers";
|
||||
import { setSelection } from "@html_editor/../tests/_helpers/selection";
|
||||
import { expandToolbar } from "@html_editor/../tests/_helpers/toolbar";
|
||||
import { insertText, pasteHtml } from "@html_editor/../tests/_helpers/user_actions";
|
||||
import { FontPlugin } from "@html_editor/main/font/font_plugin";
|
||||
import { isTextNode } from "@html_editor/utils/dom_info";
|
||||
import { parseHTML } from "@html_editor/utils/html";
|
||||
import { expect, test, describe } from "@odoo/hoot";
|
||||
import {
|
||||
click,
|
||||
manuallyDispatchProgrammaticEvent,
|
||||
waitFor,
|
||||
queryOne,
|
||||
waitForNone,
|
||||
} from "@odoo/hoot-dom";
|
||||
import { animationFrame } from "@odoo/hoot-mock";
|
||||
import { contains, patchWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
test("should add an icon from the media modal dialog", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>x</p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.document.querySelector("p");
|
||||
editor.shared.selection.focusEditable();
|
||||
editor.shared.selection.setSelection({
|
||||
anchorNode: p,
|
||||
anchorOffset: 1,
|
||||
focusNode: p,
|
||||
focusOffset: 1,
|
||||
});
|
||||
await insertText(editor, "/image");
|
||||
await animationFrame();
|
||||
await contains(".o-we-command").click();
|
||||
await contains(".modal .modal-body .nav-item:nth-child(3) a").click();
|
||||
await contains(".modal .modal-body .fa-heart").click();
|
||||
expect(p).toHaveInnerHTML(`x<span class="fa fa-heart" contenteditable="false">\u200b</span>`);
|
||||
});
|
||||
|
||||
test("should delete text forward", async () => {
|
||||
const keyPress = async (editor, key) => {
|
||||
await manuallyDispatchProgrammaticEvent(editor.editable, "keydown", { key });
|
||||
await manuallyDispatchProgrammaticEvent(editor.editable, "keyup", { key });
|
||||
};
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>abc</p><p>def</p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.editable.querySelector("p");
|
||||
editor.shared.selection.setSelection({ anchorNode: p, anchorOffset: 1 });
|
||||
await keyPress(editor, "delete");
|
||||
// paragraphs get merged
|
||||
expect(p).toHaveInnerHTML("abcdef");
|
||||
await keyPress(editor, "delete");
|
||||
// following character gets deleted
|
||||
expect(p).toHaveInnerHTML("abcef");
|
||||
});
|
||||
|
||||
test("unsplittable node predicates should not crash when called with text node argument", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>abc</p>`);
|
||||
const editor = getEditor();
|
||||
const textNode = editor.editable.querySelector("p").firstChild;
|
||||
expect(isTextNode(textNode)).toBe(true);
|
||||
expect(() =>
|
||||
editor.resources.unsplittable_node_predicates.forEach((p) => p(textNode))
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
test("should set contenteditable to false on .o_not_editable elements", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`
|
||||
<div class="o_not_editable">
|
||||
<p>abc</p>
|
||||
</div>
|
||||
`);
|
||||
const editor = getEditor();
|
||||
const div = editor.editable.querySelector("div.o_not_editable");
|
||||
expect(div).toHaveAttribute("contenteditable", "false");
|
||||
|
||||
// Add a snippet-like element
|
||||
const snippetHtml = `
|
||||
<section class="o_not_editable">
|
||||
<p>abc</p>
|
||||
</section>
|
||||
`;
|
||||
const snippet = parseHTML(editor.document, snippetHtml).firstChild;
|
||||
div.after(snippet);
|
||||
editor.shared.history.addStep();
|
||||
// Normalization should set contenteditable to false
|
||||
expect(snippet).toHaveAttribute("contenteditable", "false");
|
||||
});
|
||||
|
||||
test("should preserve iframe in the toolbar's font size input", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`
|
||||
<section class="s_text_block pt40 pb40 o_colored_level" data-snippet="s_text_block" data-name="Text">
|
||||
<div class="container s_allow_columns">
|
||||
<p>Some text.</p>
|
||||
<p>Some more text.</p>
|
||||
</div>
|
||||
</section>
|
||||
`);
|
||||
const editor = getEditor();
|
||||
const p = editor.editable.querySelector("p");
|
||||
const p2 = p.nextElementSibling;
|
||||
// Activate the text block snippet.
|
||||
click(p);
|
||||
|
||||
// Select the word "more".
|
||||
editor.shared.selection.setSelection({
|
||||
anchorNode: p2.firstChild,
|
||||
anchorOffset: 5,
|
||||
focusNode: p2.firstChild,
|
||||
focusOffset: 9,
|
||||
});
|
||||
await waitFor(".o-we-toolbar");
|
||||
// Get the font size selector input.
|
||||
let iframeEl = queryOne(".o-we-toolbar [name='font_size_selector'] iframe");
|
||||
let inputEl = iframeEl.contentWindow.document?.querySelector("input");
|
||||
// Change the font style from paragraph to paragraph.
|
||||
await contains(".o-we-toolbar .btn[name='font'].dropdown-toggle").click();
|
||||
await waitFor(".btn[name='font'].dropdown-toggle.show");
|
||||
await contains(".dropdown-menu [name='p']").click();
|
||||
iframeEl = queryOne(".o-we-toolbar [name='font_size_selector'] iframe");
|
||||
let newInputEl = iframeEl.contentWindow.document?.querySelector("input");
|
||||
expect(newInputEl).toBe(inputEl); // The input shouldn't have been changed.
|
||||
|
||||
// Select the first word "text".
|
||||
editor.shared.selection.setSelection({
|
||||
anchorNode: p.firstChild,
|
||||
anchorOffset: 5,
|
||||
focusNode: p.firstChild,
|
||||
focusOffset: 9,
|
||||
});
|
||||
await waitFor(".o-we-toolbar");
|
||||
// Get the font size selector input.
|
||||
iframeEl = queryOne(".o-we-toolbar [name='font_size_selector'] iframe");
|
||||
inputEl = iframeEl.contentWindow.document?.querySelector("input");
|
||||
// Change the font style from paragraph to header 1.
|
||||
await contains(".o-we-toolbar .btn[name='font'].dropdown-toggle").click();
|
||||
await waitFor(".btn[name='font'].dropdown-toggle.show");
|
||||
await contains(".dropdown-menu [name='h2']").click();
|
||||
iframeEl = queryOne(".o-we-toolbar [name='font_size_selector'] iframe");
|
||||
newInputEl = iframeEl.contentWindow.document?.querySelector("input");
|
||||
expect(newInputEl).toBe(inputEl); // The input shouldn't have been changed.
|
||||
});
|
||||
|
||||
test("should apply default table classes on paste", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p><br></p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.document.querySelector("p");
|
||||
editor.shared.selection.focusEditable();
|
||||
editor.shared.selection.setSelection({
|
||||
anchorNode: p,
|
||||
anchorOffset: 0,
|
||||
});
|
||||
pasteHtml(editor, `<table><tr><td>1234</td></tr></table>`);
|
||||
expect(editor.document.querySelector("table")).toHaveClass("table table-bordered");
|
||||
});
|
||||
|
||||
describe("toolbar dropdowns", () => {
|
||||
const setup = async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>abc</p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.editable.querySelector("p");
|
||||
setSelection({ anchorNode: p, anchorOffset: 0, focusOffset: 1 });
|
||||
await waitFor(".o-we-toolbar");
|
||||
await expandToolbar();
|
||||
return { editor, p };
|
||||
};
|
||||
|
||||
const focusAndClick = async (selector) => {
|
||||
const target = await waitFor(selector);
|
||||
manuallyDispatchProgrammaticEvent(target, "mousedown");
|
||||
manuallyDispatchProgrammaticEvent(target, "focus");
|
||||
await animationFrame();
|
||||
// Dropdown menu needs another animation frame to be closed after the
|
||||
// toolbar is closed.
|
||||
await animationFrame();
|
||||
expect(target).toBeVisible();
|
||||
manuallyDispatchProgrammaticEvent(target, "mouseup");
|
||||
manuallyDispatchProgrammaticEvent(target, "click");
|
||||
};
|
||||
|
||||
test("list dropdown should not close on click", async () => {
|
||||
const { editor } = await setup();
|
||||
click(".o-we-toolbar .btn[name='list_selector']");
|
||||
const bulletedListButtonSelector = ".dropdown-menu button[name='bulleted_list']";
|
||||
await focusAndClick(bulletedListButtonSelector);
|
||||
await animationFrame();
|
||||
expect(bulletedListButtonSelector).toBeVisible();
|
||||
expect(bulletedListButtonSelector).toHaveClass("active");
|
||||
expect(!!editor.editable.querySelector("ul li")).toBe(true);
|
||||
});
|
||||
|
||||
test("text alignment dropdown should not close on click", async () => {
|
||||
const { p } = await setup();
|
||||
click(".o-we-toolbar .btn[name='text_align']");
|
||||
const alignCenterButtonSelector = ".dropdown-menu button.fa-align-center";
|
||||
await focusAndClick(alignCenterButtonSelector);
|
||||
await animationFrame();
|
||||
expect(alignCenterButtonSelector).toBeVisible();
|
||||
expect(alignCenterButtonSelector).toHaveClass("active");
|
||||
expect(p).toHaveStyle("text-align: center");
|
||||
});
|
||||
|
||||
test("font style dropdown should close only after click", async () => {
|
||||
const { editor } = await setup();
|
||||
click(".o-we-toolbar .btn[name='font']");
|
||||
await focusAndClick(".dropdown-menu .dropdown-item[name='h2']");
|
||||
await animationFrame();
|
||||
expect(!!editor.editable.querySelector("h2")).toBe(true);
|
||||
});
|
||||
|
||||
test("font size dropdown should close only after click", async () => {
|
||||
patchWithCleanup(FontPlugin.prototype, {
|
||||
get fontSizeItems() {
|
||||
return [{ name: "test", className: "test-font-size" }];
|
||||
},
|
||||
});
|
||||
const { p } = await setup();
|
||||
click(".o-we-toolbar .btn[name='font_size_selector']");
|
||||
await focusAndClick(".dropdown-menu .dropdown-item");
|
||||
await animationFrame();
|
||||
expect(p.firstChild).toHaveClass("test-font-size");
|
||||
});
|
||||
|
||||
test("font selector dropdown should not have normal as an option", async () => {
|
||||
await setup();
|
||||
click(".o-we-toolbar .btn[name='font']");
|
||||
await animationFrame();
|
||||
expect(".o_font_selector_menu .o-dropdown-item[name='div']").toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("font types", () => {
|
||||
test("Header 1 Display 1 to 4 are available", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>abc</p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.editable.querySelector("p");
|
||||
setSelection({ anchorNode: p, anchorOffset: 0, focusOffset: 1 });
|
||||
await waitFor(".o-we-toolbar");
|
||||
click(".o-we-toolbar .btn[name='font']");
|
||||
await waitFor(".o_font_selector_menu");
|
||||
const expectedButtons = [
|
||||
"Header 1 Display 1",
|
||||
"Header 1 Display 2",
|
||||
"Header 1 Display 3",
|
||||
"Header 1 Display 4",
|
||||
];
|
||||
expectedButtons.forEach((button) => {
|
||||
expect(`.o_font_selector_menu .o-dropdown-item:contains('${button}')`).toHaveCount(1);
|
||||
});
|
||||
});
|
||||
test("'Light' is available", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>abc</p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.editable.querySelector("p");
|
||||
setSelection({ anchorNode: p, anchorOffset: 0, focusOffset: 1 });
|
||||
await waitFor(".o-we-toolbar");
|
||||
click(".o-we-toolbar .btn[name='font']");
|
||||
await waitFor(".o_font_selector_menu");
|
||||
expect(`.o_font_selector_menu .o-dropdown-item:contains('Light')`).toHaveCount(1);
|
||||
click(".o_font_selector_menu .o-dropdown-item:contains('Light')");
|
||||
await waitForNone(".o_font_selector_menu");
|
||||
expect(".o-we-toolbar .btn[name='font']").toHaveText("Light");
|
||||
expect(editor.editable.querySelector("p")).toHaveClass("lead");
|
||||
});
|
||||
test("'Small' is available", async () => {
|
||||
const { getEditor } = await setupHTMLBuilder(`<p>abc</p>`);
|
||||
const editor = getEditor();
|
||||
const p = editor.editable.querySelector("p");
|
||||
setSelection({ anchorNode: p, anchorOffset: 0, focusOffset: 1 });
|
||||
await waitFor(".o-we-toolbar");
|
||||
click(".o-we-toolbar .btn[name='font']");
|
||||
await waitFor(".o_font_selector_menu");
|
||||
expect(`.o_font_selector_menu .o-dropdown-item:contains('Small')`).toHaveCount(1);
|
||||
click(".o_font_selector_menu .o-dropdown-item:contains('Small')");
|
||||
await waitForNone(".o_font_selector_menu");
|
||||
expect(".o-we-toolbar .btn[name='font']").toHaveText("Small");
|
||||
expect(editor.editable.querySelector("p")).toHaveClass("small");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue