Odoo18-Base/extra-addons/web_studio/static/tests/legacy/navbar_tests.js

401 lines
14 KiB
JavaScript

/** @odoo-module **/
import { registerCleanup } from "@web/../tests/helpers/cleanup";
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import { makeFakeDialogService, makeFakePwaService } from "@web/../tests/helpers/mock_services";
import { mountInFixture } from "@web/../tests/helpers/mount_in_fixture";
import { click, getFixture, nextTick, patchWithCleanup } from "@web/../tests/helpers/utils";
import { getActionManagerServerData } from "@web/../tests/webclient/helpers";
import { browser } from "@web/core/browser/browser";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { popoverService } from "@web/core/popover/popover_service";
import { registry } from "@web/core/registry";
import { actionService } from "@web/webclient/actions/action_service";
import { companyService } from "@web/webclient/company_service";
import { menuService } from "@web/webclient/menus/menu_service";
import { createEnterpriseWebClient } from "@web_enterprise/../tests/helpers";
import { AppMenuEditor } from "@web_studio/client_action/editor/app_menu_editor/app_menu_editor";
import { NewModelItem } from "@web_studio/client_action/editor/new_model_item/new_model_item";
import { StudioNavbar } from "@web_studio/client_action/navbar/navbar";
import { leaveStudio, openStudio, registerStudioDependencies } from "./helpers";
const serviceRegistry = registry.category("services");
let target;
QUnit.module("Studio > Navbar", (hooks) => {
let baseConfig;
hooks.beforeEach(() => {
target = getFixture();
registerStudioDependencies();
serviceRegistry.add("action", actionService);
serviceRegistry.add("dialog", makeFakeDialogService());
serviceRegistry.add("pwa", makeFakePwaService());
serviceRegistry.add("menu", menuService);
serviceRegistry.add("hotkey", hotkeyService);
serviceRegistry.add("popover", popoverService);
patchWithCleanup(browser, {
setTimeout: (handler, delay, ...args) => handler(...args),
clearTimeout: () => {},
});
const menus = {
root: { id: "root", children: [1], name: "root", appID: "root" },
1: { id: 1, children: [10, 11, 12], name: "App0", appID: 1 },
10: { id: 10, children: [], name: "Section 10", appID: 1 },
11: { id: 11, children: [], name: "Section 11", appID: 1 },
12: { id: 12, children: [120, 121, 122], name: "Section 12", appID: 1 },
120: { id: 120, children: [], name: "Section 120", appID: 1 },
121: { id: 121, children: [], name: "Section 121", appID: 1 },
122: { id: 122, children: [], name: "Section 122", appID: 1 },
};
const serverData = { menus };
baseConfig = { serverData };
});
QUnit.test("menu buttons will not be placed under 'more' menu", async (assert) => {
assert.expect(12);
const menuButtonsRegistry = registry.category("studio_navbar_menubuttons");
// Force Navbar to contain those elements
registerCleanup(() => {
menuButtonsRegistry.remove("app_menu_editor");
menuButtonsRegistry.remove("new_model_item");
});
class MyStudioNavbar extends StudioNavbar {
async adapt() {
const prom = super.adapt();
const sectionsCount = this.currentAppSections.length;
const hiddenSectionsCount = this.currentAppSectionsExtra.length;
assert.step(`adapt -> hide ${hiddenSectionsCount}/${sectionsCount} sections`);
return prom;
}
}
const env = await makeTestEnv(baseConfig);
patchWithCleanup(env.services.studio, {
get mode() {
// Will force the the navbar in the studio editor state
return "editor";
},
});
menuButtonsRegistry.add(
"app_menu_editor",
{
Component: AppMenuEditor,
props: { env },
},
{ force: true }
);
menuButtonsRegistry.add("new_model_item", { Component: NewModelItem }, { force: true });
// Force the parent width, to make this test independent of screen size
target.style.width = "100%";
// Set menu and mount
env.services.menu.setCurrentMenu(1);
await mountInFixture(MyStudioNavbar, target, { env });
await nextTick();
assert.containsN(
target,
".o_menu_sections > *:not(.o_menu_sections_more):not(.d-none)",
3,
"should have 3 menu sections displayed (that are not the 'more' menu)"
);
assert.containsNone(target, ".o_menu_sections_more", "the 'more' menu should not exist");
assert.containsN(
target,
".o-studio--menu > *",
2,
"should have 2 studio menu elements displayed"
);
assert.deepEqual(
[...target.querySelectorAll(".o-studio--menu > *")].map((el) => el.innerText),
["Edit Menu", "New Model"]
);
// Force minimal width and dispatch window resize event
target.style.width = "0%";
window.dispatchEvent(new Event("resize"));
await nextTick();
assert.containsOnce(
target,
".o_menu_sections > *:not(.d-none)",
"only one menu section should be displayed"
);
assert.containsOnce(
target,
".o_menu_sections_more:not(.d-none)",
"the displayed menu section should be the 'more' menu"
);
assert.containsN(
target,
".o-studio--menu > *",
2,
"should have 2 studio menu elements displayed"
);
assert.deepEqual(
[...target.querySelectorAll(".o-studio--menu > *")].map((el) => el.innerText),
["Edit Menu", "New Model"]
);
// Open the more menu
await click(target, ".o_menu_sections_more .dropdown-toggle");
assert.deepEqual(
[...target.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
["Section 10", "Section 11", "Section 12", "Section 120", "Section 121", "Section 122"],
"'more' menu should contain all hidden sections in correct order"
);
// Check the navbar adaptation calls
assert.verifySteps(["adapt -> hide 0/3 sections", "adapt -> hide 3/3 sections"]);
});
QUnit.test("homemenu customizer rendering", async (assert) => {
assert.expect(6);
serviceRegistry.add("company", companyService);
const fakeHTTPService = {
start() {
return {};
},
};
serviceRegistry.add("http", fakeHTTPService);
const env = await makeTestEnv(baseConfig);
patchWithCleanup(env.services.studio, {
get mode() {
// Will force the navbar in the studio home_menu state
return "home_menu";
},
});
const target = getFixture();
// Set menu and mount
await mountInFixture(StudioNavbar, target, { env });
await nextTick();
assert.containsOnce(target, ".o_studio_navbar");
assert.containsOnce(target, ".o_web_studio_home_studio_menu");
assert.containsOnce(target, ".o_web_studio_change_background");
assert.strictEqual(
target.querySelector(".o_web_studio_change_background input").accept,
"image/*",
"Input should now only accept images"
);
assert.containsOnce(target, ".o_web_studio_import");
assert.containsOnce(target, ".o_web_studio_export");
});
});
QUnit.module("Studio > navbar coordination", (hooks) => {
let serverData;
let target;
hooks.beforeEach(() => {
target = getFixture();
serverData = getActionManagerServerData();
registerStudioDependencies();
serviceRegistry.add("company", companyService);
});
QUnit.test("adapt navbar when leaving studio", async (assert) => {
assert.expect(8);
patchWithCleanup(browser, {
setTimeout: (handler, delay, ...args) => handler(...args),
clearTimeout: () => {},
});
target.style.width = "1120px";
serverData.menus[1].actionID = 1;
serverData.actions[1].xml_id = "action_xml_id";
const webClient = await createEnterpriseWebClient({ serverData });
const width = document.body.style.width;
document.body.style.width = "1120px";
registerCleanup(() => {
document.body.style.width = width;
});
window.dispatchEvent(new Event("resize"));
await nextTick();
await nextTick();
await click(target.querySelector(".o_app[data-menu-xmlid=menu_1]"));
await nextTick();
await nextTick();
assert.containsNone(target, ".o_menu_sections .o_menu_sections_more");
await openStudio(target);
await nextTick();
await nextTick();
await nextTick();
assert.containsOnce(target, ".o_studio .o_menu_sections");
assert.containsNone(target, ".o_studio .o_menu_sections .o_menu_sections_more");
Object.assign(serverData.menus, {
10: {
id: 10,
children: [],
name: "The chain",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
11: {
id: 11,
children: [111],
name: "Running in the shadows, damn your love, damn your lies",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
12: {
id: 12,
children: [],
name: "You would never break the chain (Never break the chain)",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
13: {
id: 13,
children: [],
name: "Chain keep us together (running in the shadow)",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
111: {
id: 111,
children: [],
name: "You will never love me again",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
});
serverData.menus[1].children = [10, 11, 12, 13];
await webClient.env.services.menu.reload();
// two ticks to allow the navbar to adapt
await nextTick();
await nextTick();
assert.strictEqual(
target.querySelectorAll(".o_studio header .o_menu_sections > *:not(.d-none)").length,
3
);
assert.containsOnce(target, ".o_studio .o_menu_sections .o_menu_sections_more");
await leaveStudio(target);
// two more ticks to allow the navbar to adapt
await nextTick();
await nextTick();
assert.containsNone(target, ".o_studio");
assert.strictEqual(
target.querySelectorAll("header .o_menu_sections > *:not(.d-none)").length,
4
);
assert.containsOnce(target, ".o_menu_sections .o_menu_sections_more");
});
QUnit.test("adapt navbar when refreshing studio", async (assert) => {
assert.expect(7);
target.style.width = "800px";
const adapted = [];
patchWithCleanup(StudioNavbar.prototype, {
async adapt() {
const prom = super.adapt();
adapted.push(prom);
return prom;
},
});
serverData.menus[1].actionID = 1;
serverData.actions[1].xml_id = "action_xml_id";
serverData.actions[1].id = 1;
serverData.menus[1].children = [10, 11, 12, 13];
Object.assign(serverData.menus, {
10: {
id: 10,
children: [],
name: "The chain",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
11: {
id: 11,
children: [111],
name: "Running in the shadows, damn your love, damn your lies",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
12: {
id: 12,
children: [],
name: "You would never break the chain (Never break the chain)",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
13: {
id: 13,
children: [],
name: "Chain keep us together (running in the shadow)",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
111: {
id: 111,
children: [],
name: "You will never love me again",
appID: 1,
actionID: 1001,
xmlid: "menu_1",
},
});
await createEnterpriseWebClient({ serverData });
window.dispatchEvent(new Event("resize"));
await Promise.all(adapted);
await click(target.querySelector(".o_app[data-menu-xmlid=menu_1]"));
await Promise.all(adapted);
await nextTick();
await nextTick();
assert.containsNone(target, ".o_studio");
assert.strictEqual(
target.querySelectorAll("header .o_menu_sections > *:not(.d-none)").length,
3
);
assert.containsOnce(target, ".o_menu_sections .o_menu_sections_more");
await openStudio(target);
await Promise.all(adapted);
await nextTick();
assert.strictEqual(
target.querySelectorAll(".o_studio header .o_menu_sections > *:not(.d-none)").length,
2
);
assert.containsOnce(target, ".o_studio .o_menu_sections .o_menu_sections_more");
await nextTick();
browser.location.reload();
await Promise.all(adapted);
await nextTick();
assert.strictEqual(
target.querySelectorAll(".o_studio header .o_menu_sections > *:not(.d-none)").length,
2
);
assert.containsOnce(target, ".o_studio .o_menu_sections .o_menu_sections_more");
});
});