/** @odoo-module **/ import testUtils from "web.test_utils"; import core from "web.core"; import AbstractAction from "web.AbstractAction"; import { registry } from "@web/core/registry"; import { click, getFixture, patchWithCleanup, makeDeferred, nextTick } from "../../helpers/utils"; import { createWebClient, doAction, getActionManagerServerData } from "./../helpers"; import { registerCleanup } from "../../helpers/cleanup"; import { errorService } from "@web/core/errors/error_service"; import { useService } from "@web/core/utils/hooks"; import { ClientErrorDialog } from "@web/core/errors/error_dialogs"; import { Component, onMounted, xml } from "@odoo/owl"; let serverData; let target; QUnit.module("ActionManager", (hooks) => { hooks.beforeEach(() => { serverData = getActionManagerServerData(); target = getFixture(); }); QUnit.module('Actions in target="new"'); QUnit.test('can execute act_window actions in target="new"', async function (assert) { assert.expect(8); const mockRPC = async (route, args) => { assert.step((args && args.method) || route); }; const webClient = await createWebClient({ serverData, mockRPC }); await doAction(webClient, 5); assert.containsOnce( document.body, ".o_technical_modal .o_form_view", "should have rendered a form view in a modal" ); assert.hasClass( $(".o_technical_modal .modal-body")[0], "o_act_window", "dialog main element should have classname 'o_act_window'" ); assert.containsOnce( document.body, ".o_technical_modal .o_form_view .o_form_editable", "form view should be in edit mode" ); assert.verifySteps([ "/web/webclient/load_menus", "/web/action/load", "get_views", "onchange", ]); }); QUnit.test("chained action on_close", async function (assert) { assert.expect(4); function onClose(closeInfo) { assert.strictEqual(closeInfo, "smallCandle"); assert.step("Close Action"); } const webClient = await createWebClient({ serverData }); await doAction(webClient, 5, { onClose }); // a target=new action shouldn't activate the on_close await doAction(webClient, 5); assert.verifySteps([]); // An act_window_close should trigger the on_close await doAction(webClient, { type: "ir.actions.act_window_close", infos: "smallCandle" }); assert.verifySteps(["Close Action"]); }); QUnit.test("footer buttons are moved to the dialog footer", async function (assert) { assert.expect(3); serverData.views["partner,false,form"] = `
`; const webClient = await createWebClient({ serverData }); await doAction(webClient, 5); assert.containsNone( $(".o_technical_modal .modal-body")[0], "button.infooter", "the button should not be in the body" ); assert.containsOnce( $(".o_technical_modal .modal-footer")[0], "button.infooter", "the button should be in the footer" ); assert.containsOnce( target, ".modal-footer button:not(.d-none)", "the modal footer should only contain one visible button" ); }); QUnit.test("Button with `close` attribute closes dialog", async function (assert) { serverData.views = { "partner,false,form": `
`, "partner,view_ref,form": `
`, "partner,false,search": "", }; serverData.actions[4] = { id: 4, name: "Partners Action 4", res_model: "partner", type: "ir.actions.act_window", views: [[false, "form"]], }; serverData.actions[5] = { id: 5, name: "Create a Partner", res_model: "partner", target: "new", type: "ir.actions.act_window", views: [["view_ref", "form"]], }; const mockRPC = async (route, args) => { assert.step(route); if (route === "/web/dataset/call_button" && args.method === "some_method") { return { tag: "display_notification", type: "ir.actions.client", }; } }; const webClient = await createWebClient({ serverData, mockRPC }); assert.verifySteps(["/web/webclient/load_menus"]); await doAction(webClient, 4); assert.verifySteps([ "/web/action/load", "/web/dataset/call_kw/partner/get_views", "/web/dataset/call_kw/partner/onchange", ]); await testUtils.dom.click(`button[name="5"]`); assert.verifySteps([ "/web/dataset/call_kw/partner/create", "/web/dataset/call_kw/partner/read", "/web/action/load", "/web/dataset/call_kw/partner/get_views", "/web/dataset/call_kw/partner/onchange", ]); assert.containsOnce(document.body, ".modal"); await testUtils.dom.click(`button[name="some_method"]`); assert.verifySteps([ "/web/dataset/call_kw/partner/create", "/web/dataset/call_kw/partner/read", "/web/dataset/call_button", "/web/dataset/call_kw/partner/read", ]); assert.containsNone(document.body, ".modal"); }); QUnit.test('on_attach_callback is called for actions in target="new"', async function (assert) { assert.expect(3); const ClientAction = AbstractAction.extend({ on_attach_callback: function () { assert.step("on_attach_callback"); assert.containsOnce( document.body, ".modal .o_test", "should have rendered the client action in a dialog" ); }, start: function () { this.$el.addClass("o_test"); }, }); core.action_registry.add("test", ClientAction); const webClient = await createWebClient({ serverData }); await doAction(webClient, { tag: "test", target: "new", type: "ir.actions.client", }); assert.verifySteps(["on_attach_callback"]); delete core.action_registry.map.test; }); QUnit.test( 'footer buttons are updated when having another action in target "new"', async function (assert) { serverData.views["partner,false,form"] = `
`; const webClient = await createWebClient({ serverData }); await doAction(webClient, 5); assert.containsNone(target, '.o_technical_modal .modal-body button[special="save"]'); assert.containsNone(target, ".o_technical_modal .modal-body button.infooter"); assert.containsOnce(target, ".o_technical_modal .modal-footer button.infooter"); assert.containsOnce(target, ".o_technical_modal .modal-footer button:not(.d-none)"); await doAction(webClient, 25); assert.containsNone(target, ".o_technical_modal .modal-body button.infooter"); assert.containsNone(target, ".o_technical_modal .modal-footer button.infooter"); assert.containsNone(target, '.o_technical_modal .modal-body button[special="save"]'); assert.containsOnce(target, '.o_technical_modal .modal-footer button[special="save"]'); assert.containsOnce(target, ".o_technical_modal .modal-footer button:not(.d-none)"); } ); QUnit.test( 'buttons of client action in target="new" and transition to MVC action', async function (assert) { const ClientAction = AbstractAction.extend({ renderButtons($target) { const button = document.createElement("button"); button.setAttribute("class", "o_stagger_lee"); $target[0].appendChild(button); }, }); core.action_registry.add("test", ClientAction); const webClient = await createWebClient({ serverData }); await doAction(webClient, { tag: "test", target: "new", type: "ir.actions.client", }); assert.containsOnce(target, ".modal footer button.o_stagger_lee"); assert.containsNone(target, '.modal footer button[special="save"]'); await doAction(webClient, 25); assert.containsNone(target, ".modal footer button.o_stagger_lee"); assert.containsOnce(target, '.modal footer button[special="save"]'); delete core.action_registry.map.test; } ); QUnit.test( 'button with confirm attribute in act_window action in target="new"', async function (assert) { serverData.actions[999] = { id: 999, name: "A window action", res_model: "partner", target: "new", type: "ir.actions.act_window", views: [[999, "form"]], }; serverData.views["partner,999,form"] = `