import {
addBuilderPlugin,
addBuilderOption,
addBuilderAction,
setupHTMLBuilder,
} from "@html_builder/../tests/helpers";
import { BuilderAction } from "@html_builder/core/builder_action";
import { Plugin } from "@html_editor/plugin";
import { expect, test, describe } from "@odoo/hoot";
import { xml } from "@odoo/owl";
import { contains } from "@web/../tests/web_test_helpers";
describe.current.tags("desktop");
test("Undo/Redo correctly restores the stored container target", async () => {
addBuilderAction({
customAction: class extends BuilderAction {
static id = "customAction";
apply({ editingElement }) {
editingElement.remove();
}
},
});
addBuilderOption({
selector: ".test-options-target",
template: xml`Test`,
});
await setupHTMLBuilder(`
Homepage
Homepage2
`);
await contains(":iframe .target1").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains("[data-action-id='customAction']").click();
await contains(":iframe .target2").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
await contains(".o-snippets-top-actions .fa-undo").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains(".o-snippets-top-actions .fa-repeat").click();
expect(".options-container").toHaveCount(0);
});
test("Undo/Redo multiple actions always restores the action container target", async () => {
addBuilderAction({
customAction: class extends BuilderAction {
static id = "customAction";
apply({ editingElement }) {
editingElement.classList.add("test");
}
},
});
addBuilderOption({
selector: ".test-options-target",
template: xml`Test`,
});
await setupHTMLBuilder(`
Homepage
Homepage2
`);
await contains(":iframe .target1").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains("[data-action-id='customAction']").click();
await contains(":iframe .target2").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
await contains("[data-action-id='customAction']").click();
expect(":iframe .test-options-target.test").toHaveCount(2);
// Undo everything.
await contains(".o-snippets-top-actions .fa-undo").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
await contains(".o-snippets-top-actions .fa-undo").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
expect(":iframe .test-options-target.test").toHaveCount(0);
// Redo everything.
await contains(".o-snippets-top-actions .fa-repeat").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains(".o-snippets-top-actions .fa-repeat").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
expect(":iframe .test-options-target.test").toHaveCount(2);
});
test("Undo/Redo an action that activates another target restores the old one on undo and the new one on redo", async () => {
let editor;
addBuilderAction({
customAction: class extends BuilderAction {
static id = "customAction";
apply({ editingElement }) {
editingElement.classList.add("test");
editor.shared.builderOptions.setNextTarget(editingElement.nextElementSibling);
}
},
});
addBuilderOption({
selector: ".test-options-target",
template: xml`Test`,
});
const { getEditor } = await setupHTMLBuilder(`
Homepage
Homepage2
`);
editor = getEditor();
await contains(":iframe .target1").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains("[data-action-id='customAction']").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
// Undo everything.
await contains(".o-snippets-top-actions .fa-undo").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains(".o-snippets-top-actions .fa-repeat").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
});
test("Undo/Redo an action that deactivates the containers restores the old one on undo and deactivates again on redo", async () => {
let editor;
addBuilderAction({
customAction: class extends BuilderAction {
static id = "customAction";
apply({ editingElement }) {
editingElement.classList.add("test");
editor.shared.builderOptions.setNextTarget(false);
}
},
});
addBuilderOption({
selector: ".test-options-target",
template: xml`Test`,
});
const { getEditor } = await setupHTMLBuilder(`
Homepage
`);
editor = getEditor();
await contains(":iframe .target1").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains("[data-action-id='customAction']").click();
expect(".options-container").toHaveCount(0);
expect("button[data-name='blocks']").toHaveClass("active");
// Undo everything.
await contains(".o-snippets-top-actions .fa-undo").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 1");
await contains(".o-snippets-top-actions .fa-repeat").click();
expect(".options-container").toHaveCount(0);
expect("button[data-name='blocks']").toHaveClass("active");
});
test("Containers fallback to a valid ancestor if the target disappears and restore it on undo", async () => {
addBuilderAction({
targetAction: class extends BuilderAction {
static id = "targetAction";
apply({ editingElement }) {
editingElement.remove();
}
},
ancestorAction: class extends BuilderAction {
static id = "ancestorAction";
apply({ editingElement }) {
editingElement.remove();
}
},
});
addBuilderOption({
selector: ".test-options-target",
template: xml`Test`,
});
addBuilderOption({
selector: ".test-ancestor",
template: xml`Ancestor selected`,
});
await setupHTMLBuilder(`
Hey I'm an ancestor
Homepage
`);
await contains(":iframe .target1").click();
expect(".options-container[data-container-title='Ancestor']").toHaveCount(1);
expect(".options-container[data-container-title='Target 1']").toHaveCount(1);
await contains("[data-action-id='targetAction']").click();
expect(".options-container[data-container-title='Ancestor']").toHaveCount(1);
expect(".options-container[data-container-title='Target 1']").toHaveCount(0);
expect("[data-action-id='ancestorAction']").toHaveCount(1);
await contains(".o-snippets-top-actions .fa-undo").click();
expect(".options-container[data-container-title='Ancestor']").toHaveCount(1);
expect(".options-container[data-container-title='Target 1']").toHaveCount(1);
});
test("Do not activate/update containers if the element clicked is excluded", async () => {
addBuilderOption({
selector: ".test-options-target",
template: xml`Test`,
});
await setupHTMLBuilder(`
Homepage
Homepage2
`);
await contains(":iframe .target1").click();
expect(".options-container").toHaveCount(0);
await contains(":iframe .target2").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
expect(".options-container [data-class-action='test']").toHaveCount(1);
await contains(":iframe .target1").click();
expect(".options-container").toHaveAttribute("data-container-title", "Target 2");
});
test("Do not show parent container for no_parent_containers targets", async () => {
class TestPlugin extends Plugin {
static id = "test";
resources = {
no_parent_containers: ".test-child-target",
};
}
addBuilderPlugin(TestPlugin);
addBuilderOption({
selector: ".test-parent-target",
template: xml`Test`,
});
addBuilderOption({
selector: ".test-child-target",
template: xml`Test`,
});
addBuilderOption({
selector: ".test-grand-child-target",
template: xml`Test`,
});
await setupHTMLBuilder(`
`);
await contains(":iframe .test-child-target").click();
expect(".options-container").toHaveCount(1);
expect(".options-container").toHaveAttribute("data-container-title", "Child");
// Try with several layers
await contains(":iframe .test-grand-child-target").click();
expect(".options-container").toHaveCount(2);
expect(".options-container:eq(0)").toHaveAttribute("data-container-title", "Child");
expect(".options-container:eq(1)").toHaveAttribute("data-container-title", "Grand-child");
// Make sure the parent's options still appear for itself.
await contains(":iframe .test-parent-target").click();
expect(".options-container").toHaveCount(1);
expect(".options-container").toHaveAttribute("data-container-title", "Parent");
});