/** @odoo-module **/ import { browser } from "@web/core/browser/browser"; import { registry } from "@web/core/registry"; import testUtils from "@web/../tests/legacy/helpers/test_utils"; import { click, getFixture, nextTick, patchWithCleanup } from "../../helpers/utils"; import { createWebClient, doAction, getActionManagerServerData } from "./../helpers"; import { Component, onMounted, xml } from "@odoo/owl"; let serverData; let target; const actionRegistry = registry.category("actions"); QUnit.module("ActionManager", (hooks) => { hooks.beforeEach(() => { serverData = getActionManagerServerData(); target = getFixture(); }); QUnit.module("Client Actions"); QUnit.test("can display client actions in Dialog", async function (assert) { assert.expect(2); const webClient = await createWebClient({ serverData }); await doAction(webClient, { name: "Dialog Test", target: "new", tag: "__test__client__action__", type: "ir.actions.client", }); assert.containsOnce(target, ".modal .test_client_action"); assert.strictEqual(target.querySelector(".modal-title").textContent, "Dialog Test"); }); QUnit.test( "can display client actions in Dialog and close the dialog", async function (assert) { assert.expect(3); const webClient = await createWebClient({ serverData }); await doAction(webClient, { name: "Dialog Test", target: "new", tag: "__test__client__action__", type: "ir.actions.client", }); assert.containsOnce(target, ".modal .test_client_action"); assert.strictEqual(target.querySelector(".modal-title").textContent, "Dialog Test"); target.querySelector(".modal footer .btn.btn-primary").click(); await nextTick(); assert.containsNone(target, ".modal .test_client_action"); } ); QUnit.test("can display client actions as main, then in Dialog", async function (assert) { assert.expect(3); const webClient = await createWebClient({ serverData }); await doAction(webClient, "__test__client__action__"); assert.containsOnce(target, ".o_action_manager .test_client_action"); await doAction(webClient, { target: "new", tag: "__test__client__action__", type: "ir.actions.client", }); assert.containsOnce(target, ".o_action_manager .test_client_action"); assert.containsOnce(target, ".modal .test_client_action"); }); QUnit.test( "can display client actions in Dialog, then as main destroys Dialog", async function (assert) { assert.expect(4); const webClient = await createWebClient({ serverData }); await doAction(webClient, { target: "new", tag: "__test__client__action__", type: "ir.actions.client", }); assert.containsOnce(target, ".test_client_action"); assert.containsOnce(target, ".modal .test_client_action"); await doAction(webClient, "__test__client__action__"); assert.containsOnce(target, ".test_client_action"); assert.containsNone(target, ".modal .test_client_action"); } ); QUnit.test("soft_reload will refresh data", async (assert) => { const mockRPC = async function (route, args) { if (route === "/web/dataset/call_kw/partner/web_search_read") { assert.step("web_search_read"); } }; const webClient = await createWebClient({ serverData, mockRPC }); await doAction(webClient, 1); assert.verifySteps(["web_search_read"]); await doAction(webClient, "soft_reload"); assert.verifySteps(["web_search_read"]); }); QUnit.test("soft_reload when there is no controller", async (assert) => { const webClient = await createWebClient({ serverData }); await doAction(webClient, "soft_reload"); assert.ok(true, "No ControllerNotFoundError when there is no controller to restore"); }); QUnit.test("can execute client actions from tag name", async function (assert) { assert.expect(4); class ClientAction extends Component {} ClientAction.template = xml`
Hello World
`; actionRegistry.add("HelloWorldTest", ClientAction); const mockRPC = async function (route, args) { assert.step((args && args.method) || route); }; const webClient = await createWebClient({ serverData, mockRPC }); await doAction(webClient, "HelloWorldTest"); assert.containsNone( document.body, ".o_control_panel", "shouldn't have rendered a control panel" ); assert.strictEqual( $(target).find(".o_client_action_test").text(), "Hello World", "should have correctly rendered the client action" ); assert.verifySteps(["/web/webclient/load_menus"]); }); QUnit.test("async client action (function) returning another action", async function (assert) { assert.expect(1); registry.category("actions").add("my_action", async () => { await Promise.resolve(); return 1; // execute action 1 }); const webClient = await createWebClient({ serverData }); await doAction(webClient, "my_action"); assert.containsOnce(target, ".o_kanban_view"); }); QUnit.test( "'CLEAR-UNCOMMITTED-CHANGES' is not triggered for function client actions", async function (assert) { assert.expect(2); registry.category("actions").add("my_action", async () => { assert.step("my_action"); }); const webClient = await createWebClient({ serverData }); webClient.env.bus.addEventListener("CLEAR-UNCOMMITTED-CHANGES", () => { assert.step("CLEAR-UNCOMMITTED-CHANGES"); }); await doAction(webClient, "my_action"); assert.verifySteps(["my_action"]); } ); QUnit.test("ClientAction receives breadcrumbs and exports title", async (assert) => { assert.expect(4); class ClientAction extends Component { setup() { this.breadcrumbTitle = "myOwlAction"; const { breadcrumbs } = this.env.config; assert.strictEqual(breadcrumbs.length, 2); assert.strictEqual(breadcrumbs[0].name, "Favorite Ponies"); onMounted(() => { this.env.config.setDisplayName(this.breadcrumbTitle); }); } onClick() { this.breadcrumbTitle = "newOwlTitle"; this.env.config.setDisplayName(this.breadcrumbTitle); } } ClientAction.template = xml`
owl client action
`; actionRegistry.add("OwlClientAction", ClientAction); const webClient = await createWebClient({ serverData }); await doAction(webClient, 8); await doAction(webClient, "OwlClientAction"); assert.containsOnce(target, ".my_owl_action"); await click(target, ".my_owl_action"); await doAction(webClient, 3); assert.strictEqual( target.querySelector(".o_breadcrumb").textContent, "Favorite PoniesnewOwlTitlePartners" ); }); QUnit.test("ClientAction receives arbitrary props from doAction", async (assert) => { assert.expect(1); class ClientAction extends Component { setup() { assert.strictEqual(this.props.division, "bell"); } } ClientAction.template = xml`
`; actionRegistry.add("OwlClientAction", ClientAction); const webClient = await createWebClient({ serverData }); await doAction(webClient, "OwlClientAction", { props: { division: "bell" }, }); }); QUnit.test("test display_notification client action", async function (assert) { assert.expect(6); const webClient = await createWebClient({ serverData }); await doAction(webClient, 1); assert.containsOnce(target, ".o_kanban_view"); await doAction(webClient, { type: "ir.actions.client", tag: "display_notification", params: { title: "title", message: "message", sticky: true, }, }); await nextTick(); // wait for the notification to be displayed const notificationSelector = ".o_notification_manager .o_notification"; assert.containsOnce( document.body, notificationSelector, "a notification should be present" ); const notificationElement = document.body.querySelector(notificationSelector); assert.strictEqual( notificationElement.querySelector(".o_notification_title").textContent, "title", "the notification should have the correct title" ); assert.strictEqual( notificationElement.querySelector(".o_notification_content").textContent, "message", "the notification should have the correct message" ); assert.containsOnce(target, ".o_kanban_view"); await testUtils.dom.click(notificationElement.querySelector(".o_notification_close")); assert.containsNone( document.body, notificationSelector, "the notification should be destroy " ); }); QUnit.test("test display_notification client action with links", async function (assert) { assert.expect(8); const webClient = await createWebClient({ serverData }); await doAction(webClient, 1); assert.containsOnce(target, ".o_kanban_view"); await doAction(webClient, { type: "ir.actions.client", tag: "display_notification", params: { title: "title", message: "message %s ", sticky: true, links: [ { label: "test ", url: "#action={action.id}&id={order.id}&model=purchase.order", }, ], }, }); await nextTick(); // wait for the notification to be displayed const notificationSelector = ".o_notification_manager .o_notification"; assert.containsOnce( document.body, notificationSelector, "a notification should be present" ); let notificationElement = document.body.querySelector(notificationSelector); assert.strictEqual( notificationElement.querySelector(".o_notification_title").textContent, "title", "the notification should have the correct title" ); assert.strictEqual( notificationElement.querySelector(".o_notification_content").textContent, "message test ", "the notification should have the correct message" ); assert.containsOnce(target, ".o_kanban_view"); await testUtils.dom.click(notificationElement.querySelector(".o_notification_close")); assert.containsNone( document.body, notificationSelector, "the notification should be destroy " ); // display_notification without title await doAction(webClient, { type: "ir.actions.client", tag: "display_notification", params: { message: "message %s ", sticky: true, links: [ { label: "test ", url: "#action={action.id}&id={order.id}&model=purchase.order", }, ], }, }); await nextTick(); // wait for the notification to be displayed assert.containsOnce( document.body, notificationSelector, "a notification should be present" ); notificationElement = document.body.querySelector(notificationSelector); assert.containsNone( notificationElement, ".o_notification_title", "the notification should not have title" ); }); QUnit.test("test next action on display_notification client action", async function (assert) { const webClient = await createWebClient({ serverData }); const options = { onClose: function () { assert.step("onClose"); }, }; await doAction( webClient, { type: "ir.actions.client", tag: "display_notification", params: { title: "title", message: "message", sticky: true, next: { type: "ir.actions.act_window_close", }, }, }, options ); await nextTick(); // wait for the notification to be displayed const notificationSelector = ".o_notification_manager .o_notification"; assert.containsOnce( document.body, notificationSelector, "a notification should be present" ); assert.verifySteps(["onClose"]); }); QUnit.test("test reload client action", async function (assert) { patchWithCleanup(browser.location, { assign: (url) => { assert.step(url); }, origin: "", hash: "#test=42", }); const webClient = await createWebClient({ serverData }); await doAction(webClient, { type: "ir.actions.client", tag: "reload", }); await doAction(webClient, { type: "ir.actions.client", tag: "reload", params: { action_id: 2, }, }); await doAction(webClient, { type: "ir.actions.client", tag: "reload", params: { menu_id: 1, }, }); await doAction(webClient, { type: "ir.actions.client", tag: "reload", params: { action_id: 1, menu_id: 2, }, }); assert.verifySteps([ "/web/tests?reload=true#test=42", "/web/tests?reload=true#action=2", "/web/tests?reload=true#menu_id=1", "/web/tests?reload=true#menu_id=2&action=1", ]); }); });