/** @odoo-module */ import { click, nextTick, patchWithCleanup } from "@web/../tests/helpers/utils"; import { session } from "@web/session"; import { getBasicData } from "@spreadsheet/../tests/utils/data"; import { createBasicChart } from "@spreadsheet/../tests/utils/commands"; import { registry } from "@web/core/registry"; import { menuService } from "@web/webclient/menus/menu_service"; import { actionService } from "@web/webclient/actions/action_service"; import { mountSpreadsheet } from "@spreadsheet/../tests/utils/ui"; import { createModelWithDataSource } from "@spreadsheet/../tests/utils/model"; import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services"; const chartId = "uuid1"; /** * The chart menu is hidden by default, and visible on :hover, but this property * can't be triggered programmatically, so we artificially make it visible to be * able to interact with it. */ async function showChartMenu(fixture) { const chartMenu = fixture.querySelector(".o-figure-menu"); chartMenu.style.display = "flex"; await nextTick(); } /** Click on external link of the first chart found in the page*/ async function clickChartExternalLink(fixture) { await showChartMenu(fixture); const chartMenuItem = fixture.querySelector(".o-figure-menu-item.o-chart-external-link"); await click(chartMenuItem); } function mockActionService(assert, doActionStep) { const serviceRegistry = registry.category("services"); serviceRegistry.add("actionMain", actionService); const fakeActionService = { dependencies: ["actionMain"], start(env, { actionMain }) { return { ...actionMain, doAction: (actionRequest, options = {}) => { if (actionRequest === "menuAction2") { assert.step(doActionStep); } return actionMain.doAction(actionRequest, options); }, }; }, }; serviceRegistry.add("action", fakeActionService, { force: true, }); } QUnit.module( "spreadsheet > ir.ui.menu chart figure", { beforeEach: function () { this.serverData = {}; this.serverData.menus = { root: { id: "root", children: [1, 2], name: "root", appID: "root", }, 1: { id: 1, children: [], name: "test menu 1", xmlid: "documents_spreadsheet.test.menu", appID: 1, actionID: "menuAction", }, 2: { id: 2, children: [], name: "test menu 2", xmlid: "documents_spreadsheet.test.menu2", appID: 1, actionID: "menuAction2", }, 3: { id: 3, children: [], name: "test menu 2", xmlid: "documents_spreadsheet.test.menu_without_action", appID: 1, }, }; this.serverData.actions = { menuAction: { id: 99, xml_id: "ir.ui.menu", name: "menuAction", res_model: "ir.ui.menu", type: "ir.actions.act_window", views: [[false, "list"]], }, menuAction2: { id: 100, xml_id: "ir.ui.menu", name: "menuAction2", res_model: "ir.ui.menu", type: "ir.actions.act_window", views: [[false, "list"]], }, }; this.serverData.views = {}; this.serverData.views["ir.ui.menu,false,list"] = ``; this.serverData.views["ir.ui.menu,false,search"] = ``; this.serverData.models = { ...getBasicData(), "ir.ui.menu": { fields: { name: { string: "Name", type: "char" }, action: { string: "Action", type: "char" }, groups_id: { string: "Groups", type: "many2many", relation: "res.group", }, }, records: [ { id: 1, name: "test menu 1", action: "action1", groups_id: [10], }, { id: 2, name: "test menu 2", action: "action2", groups_id: [10], }, ], }, "res.users": { fields: { name: { string: "Name", type: "char" }, groups_id: { string: "Groups", type: "many2many", relation: "res.group", }, }, records: [{ id: 1, name: "Raoul", groups_id: [10] }], }, "ir.actions": { fields: { name: { string: "Name", type: "char" }, }, records: [{ id: 1 }], }, "res.group": { fields: { name: { string: "Name", type: "char" } }, records: [{ id: 10, name: "test group" }], }, }; patchWithCleanup(session, { uid: 1 }); registry.category("services").add("menu", menuService).add("action", actionService); }, }, () => { QUnit.test( "icon external link isn't on the chart when its not linked to an odoo menu", async function (assert) { const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); await nextTick(); const odooMenu = model.getters.getChartOdooMenu(chartId); assert.equal(odooMenu, undefined, "No menu linked with the chart"); const externalRefIcon = fixture.querySelector(".o-chart-external-link"); assert.equal(externalRefIcon, null); } ); QUnit.test( "icon external link is on the chart when its linked to an odoo menu", async function (assert) { const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: 1, }); const chartMenu = model.getters.getChartOdooMenu(chartId); assert.equal(chartMenu.id, 1, "Odoo menu is linked to chart"); await nextTick(); const externalRefIcon = fixture.querySelector(".o-chart-external-link"); assert.ok(externalRefIcon); } ); QUnit.test( "icon external link is not on the chart when its linked to a wrong odoo menu", async function (assert) { const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: "menu which does not exist", }); const chartMenu = model.getters.getChartOdooMenu(chartId); assert.equal(chartMenu, undefined, "cannot get a wrong menu"); await nextTick(); assert.containsNone(fixture, ".o-chart-external-link"); } ); QUnit.test( "icon external link isn't on the chart in dashboard mode", async function (assert) { const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: 1, }); const chartMenu = model.getters.getChartOdooMenu(chartId); assert.equal(chartMenu.id, 1, "Odoo menu is linked to chart"); model.updateMode("dashboard"); await nextTick(); assert.containsNone(fixture, ".o-chart-external-link", "No link icon in dashboard"); } ); QUnit.test( "click on icon external link on chart redirect to the odoo menu", async function (assert) { const doActionStep = "doAction"; mockActionService(assert, doActionStep); const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: 2, }); const chartMenu = model.getters.getChartOdooMenu(chartId); assert.equal(chartMenu.id, 2, "Odoo menu is linked to chart"); await nextTick(); await clickChartExternalLink(fixture); assert.verifySteps([doActionStep]); } ); QUnit.test( "Click on chart in dashboard mode redirect to the odoo menu", async function (assert) { const doActionStep = "doAction"; mockActionService(assert, doActionStep); const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: 2, }); const chartMenu = model.getters.getChartOdooMenu(chartId); assert.equal(chartMenu.id, 2, "Odoo menu is linked to chart"); await nextTick(); await click(fixture, ".o-chart-container"); assert.verifySteps([], "Clicking on a chart while not dashboard mode do nothing"); model.updateMode("dashboard"); await nextTick(); await click(fixture, ".o-chart-container"); assert.verifySteps( [doActionStep], "Clicking on a chart while on dashboard mode redirect to the odoo menu" ); } ); QUnit.test("can use menus xmlIds instead of menu ids", async function (assert) { const serviceRegistry = registry.category("services"); serviceRegistry.add("actionMain", actionService); const fakeActionService = { dependencies: ["actionMain"], start(env, { actionMain }) { return { ...actionMain, doAction: (actionRequest, options = {}) => { if (actionRequest === "menuAction2") { assert.step("doAction"); } return actionMain.doAction(actionRequest, options); }, }; }, }; serviceRegistry.add("action", fakeActionService, { force: true, }); const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: "documents_spreadsheet.test.menu2", }); await nextTick(); await clickChartExternalLink(fixture); assert.verifySteps(["doAction"]); }); QUnit.test( "Trying to open a menu without an action sends a notification to the user", async function (assert) { mockActionService(assert, "doAction"); const notificationMock = (message) => { assert.step(message); return () => {}; }; const notificationService = makeFakeNotificationService(notificationMock); registry.category("services").add("notification", notificationService, { force: true, }); const model = await createModelWithDataSource({ serverData: this.serverData, }); const fixture = await mountSpreadsheet(model); createBasicChart(model, chartId); model.dispatch("LINK_ODOO_MENU_TO_CHART", { chartId, odooMenuId: "documents_spreadsheet.test.menu_without_action", }); await nextTick(); await clickChartExternalLink(fixture); const expectedNotificationMessage = "The menu linked to this chart doesn't have an corresponding action. Please link the chart to another menu."; assert.verifySteps( [expectedNotificationMessage], "Notification was send and doAction wasn't called" ); } ); } );