/** @odoo-module **/ import { registerCleanup } from "@web/../tests/helpers/cleanup"; import { makeTestEnv } from "@web/../tests/helpers/mock_env"; import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services"; import { getFixture, nextTick, triggerHotkey, patchWithCleanup } from "@web/../tests/helpers/utils"; import { commandService } from "@web/core/commands/command_service"; import { hotkeyService } from "@web/core/hotkeys/hotkey_service"; import { ormService } from "@web/core/orm_service"; import { registry } from "@web/core/registry"; import { uiService } from "@web/core/ui/ui_service"; import { HomeMenu } from "@web_enterprise/webclient/home_menu/home_menu"; import testUtils from "web.test_utils"; import { enterpriseSubscriptionService } from "@web_enterprise/webclient/home_menu/enterprise_subscription_service"; import { session } from "@web/session"; import { templates } from "@web/core/assets"; const { App, EventBus } = owl; const patchDate = testUtils.mock.patchDate; const serviceRegistry = registry.category("services"); let target; // ----------------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------------- async function createHomeMenu(homeMenuProps) { const env = await makeTestEnv(); const app = new App(HomeMenu, { env, props: homeMenuProps, templates, test: true, }); const homeMenu = await app.mount(target); registerCleanup(() => app.destroy()); return homeMenu; } async function walkOn(assert, path) { for (const step of path) { triggerHotkey(`${step.shiftKey ? "shift+" : ""}${step.key}`); await nextTick(); assert.hasClass( target.querySelectorAll(".o_menuitem")[step.index], "o_focused", `step ${step.number}` ); } } // ----------------------------------------------------------------------------- // Tests // ----------------------------------------------------------------------------- let homeMenuProps; let bus; QUnit.module( "web_enterprise", { beforeEach: function () { homeMenuProps = { apps: [ { actionID: 121, appID: 1, id: 1, label: "Discuss", parents: "", webIcon: false, xmlid: "app.1", }, { actionID: 122, appID: 2, id: 2, label: "Calendar", parents: "", webIcon: false, xmlid: "app.2", }, { actionID: 123, appID: 3, id: 3, label: "Contacts", parents: "", webIcon: false, xmlid: "app.3", }, ], }; bus = new EventBus(); const fakeHomeMenuService = { name: "home_menu", start() { return { toggle(show) { bus.trigger("toggle", show); }, }; }, }; const fakeMenuService = { name: "menu", start() { return { selectMenu(menu) { bus.trigger("selectMenu", menu.id); }, getMenu() { return {}; }, }; }, }; serviceRegistry.add("ui", uiService); serviceRegistry.add("hotkey", hotkeyService); serviceRegistry.add("command", commandService); serviceRegistry.add("localization", makeFakeLocalizationService()); serviceRegistry.add("orm", ormService); serviceRegistry.add(enterpriseSubscriptionService.name, enterpriseSubscriptionService); serviceRegistry.add(fakeHomeMenuService.name, fakeHomeMenuService); serviceRegistry.add(fakeMenuService.name, fakeMenuService); target = getFixture(); }, }, function () { QUnit.module("HomeMenu"); QUnit.test("ESC Support", async function (assert) { bus.on("toggle", null, (show) => { assert.step(`toggle ${show}`); }); await createHomeMenu(homeMenuProps); await testUtils.dom.triggerEvent(window, "keydown", { key: "Escape" }); assert.verifySteps(["toggle false"]); }); QUnit.test("Click on an app", async function (assert) { bus.on("selectMenu", null, (menuId) => { assert.step(`selectMenu ${menuId}`); }); await createHomeMenu(homeMenuProps); await testUtils.dom.click(target.querySelectorAll(".o_menuitem")[0]); assert.verifySteps(["selectMenu 1"]); }); QUnit.test("Display Expiration Panel (no module installed)", async function (assert) { const unpatchDate = patchDate(2019, 9, 10, 0, 0, 0); registerCleanup(unpatchDate); patchWithCleanup(session, { expiration_date: "2019-11-01 12:00:00", expiration_reason: "", isMailInstalled: false, warning: "admin", }); let cookie = false; const mockedCookieService = { name: "cookie", start() { return { get current() { return cookie; }, setCookie() { cookie = true; }, }; }, }; serviceRegistry.add(mockedCookieService.name, mockedCookieService); await createHomeMenu(homeMenuProps); assert.containsOnce(target, ".database_expiration_panel"); assert.strictEqual( target.querySelector(".database_expiration_panel .oe_instance_register").innerText, "You will be able to register your database once you have installed your first app.", "There should be an expiration panel displayed" ); // Close the expiration panel await testUtils.dom.click( target.querySelector(".database_expiration_panel .oe_instance_hide_panel") ); assert.containsNone(target, ".database_expiration_panel"); }); QUnit.test("Navigation (only apps, only one line)", async function (assert) { assert.expect(8); homeMenuProps = { apps: new Array(3).fill().map((x, i) => { return { actionID: 120 + i, appID: i + 1, id: i + 1, label: `0${i}`, parents: "", webIcon: false, xmlid: `app.${i}`, }; }), }; await createHomeMenu(homeMenuProps); const path = [ { number: 0, key: "ArrowDown", index: 0 }, { number: 1, key: "ArrowRight", index: 1 }, { number: 2, key: "Tab", index: 2 }, { number: 3, key: "ArrowRight", index: 0 }, { number: 4, key: "Tab", shiftKey: true, index: 2 }, { number: 5, key: "ArrowLeft", index: 1 }, { number: 6, key: "ArrowDown", index: 1 }, { number: 7, key: "ArrowUp", index: 1 }, ]; await walkOn(assert, path); }); QUnit.test("Navigation (only apps, two lines, one incomplete)", async function (assert) { assert.expect(19); homeMenuProps = { apps: new Array(8).fill().map((x, i) => { return { actionID: 121, appID: i + 1, id: i + 1, label: `0${i}`, parents: "", webIcon: false, xmlid: `app.${i}`, }; }), }; await createHomeMenu(homeMenuProps); const path = [ { number: 1, key: "ArrowRight", index: 0 }, { number: 2, key: "ArrowUp", index: 6 }, { number: 3, key: "ArrowUp", index: 0 }, { number: 4, key: "ArrowDown", index: 6 }, { number: 5, key: "ArrowDown", index: 0 }, { number: 6, key: "ArrowRight", index: 1 }, { number: 7, key: "ArrowRight", index: 2 }, { number: 8, key: "ArrowUp", index: 7 }, { number: 9, key: "ArrowUp", index: 1 }, { number: 10, key: "ArrowRight", index: 2 }, { number: 11, key: "ArrowDown", index: 7 }, { number: 12, key: "ArrowDown", index: 1 }, { number: 13, key: "ArrowUp", index: 7 }, { number: 14, key: "ArrowRight", index: 6 }, { number: 15, key: "ArrowLeft", index: 7 }, { number: 16, key: "ArrowUp", index: 1 }, { number: 17, key: "ArrowLeft", index: 0 }, { number: 18, key: "ArrowLeft", index: 5 }, { number: 19, key: "ArrowRight", index: 0 }, ]; await walkOn(assert, path); }); QUnit.test("Navigation and open an app in the home menu", async function (assert) { assert.expect(7); bus.on("selectMenu", null, (menuId) => { assert.step(`selectMenu ${menuId}`); }); await createHomeMenu(homeMenuProps); // No app selected so nothing to open await testUtils.dom.triggerEvent(window, "keydown", { key: "Enter" }); assert.verifySteps([]); const path = [ { number: 0, key: "ArrowDown", index: 0 }, { number: 1, key: "ArrowRight", index: 1 }, { number: 2, key: "Tab", index: 2 }, { number: 3, key: "shift+Tab", index: 1 }, ]; await walkOn(assert, path); // open first app (Calendar) await testUtils.dom.triggerEvent(window, "keydown", { key: "Enter" }); assert.verifySteps(["selectMenu 2"]); }); QUnit.test( "The HomeMenu input takes the focus when you press a key only if no other element is the activeElement", async function (assert) { const target = getFixture(); const homeMenu = await createHomeMenu(homeMenuProps); const input = target.querySelector(".o_search_hidden"); assert.strictEqual(document.activeElement, input); const activeElement = document.createElement("div"); homeMenu.env.services.ui.activateElement(activeElement); // remove the focus from the input const otherInput = document.createElement("input"); target.querySelector(".o_home_menu").appendChild(otherInput); otherInput.focus(); otherInput.blur(); assert.notEqual(document.activeElement, input); await testUtils.dom.triggerEvent(window, "keydown", { key: "a" }); await nextTick(); assert.notEqual(document.activeElement, input); homeMenu.env.services.ui.deactivateElement(activeElement); await testUtils.dom.triggerEvent(window, "keydown", { key: "a" }); await nextTick(); assert.strictEqual(document.activeElement, input); } ); QUnit.test( "The HomeMenu input does not take the focus if it is already on another input", async function (assert) { const target = getFixture(); await createHomeMenu(homeMenuProps); const homeMenuInput = target.querySelector(".o_search_hidden"); assert.strictEqual(document.activeElement, homeMenuInput); const otherInput = document.createElement("input"); target.querySelector(".o_home_menu").appendChild(otherInput); otherInput.focus(); await testUtils.dom.triggerEvent(window, "keydown", { key: "a" }); await nextTick(); assert.notEqual(document.activeElement, homeMenuInput); otherInput.remove(); await testUtils.dom.triggerEvent(window, "keydown", { key: "a" }); await nextTick(); assert.strictEqual(document.activeElement, homeMenuInput); } ); QUnit.test( "The HomeMenu input does not take the focus if it is already on a textarea", async function (assert) { const target = getFixture(); await createHomeMenu(homeMenuProps); const homeMenuInput = target.querySelector(".o_search_hidden"); assert.strictEqual(document.activeElement, homeMenuInput); const textarea = document.createElement("textarea"); target.querySelector(".o_home_menu").appendChild(textarea); textarea.focus(); await testUtils.dom.triggerEvent(window, "keydown", { key: "a" }); await nextTick(); assert.notEqual(document.activeElement, homeMenuInput); textarea.remove(); await testUtils.dom.triggerEvent(window, "keydown", { key: "a" }); await nextTick(); assert.strictEqual(document.activeElement, homeMenuInput); } ); } );