674 lines
27 KiB
JavaScript
674 lines
27 KiB
JavaScript
/** @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"] = `
|
|
<form>
|
|
<field name="display_name"/>
|
|
<footer>
|
|
<button string="Create" type="object" class="infooter"/>
|
|
</footer>
|
|
</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": `
|
|
<form>
|
|
<header>
|
|
<button string="Open dialog" name="5" type="action"/>
|
|
</header>
|
|
</form>`,
|
|
"partner,view_ref,form": `
|
|
<form>
|
|
<footer>
|
|
<button string="I close the dialog" name="some_method" type="object" close="1"/>
|
|
</footer>
|
|
</form>`,
|
|
"partner,false,search": "<search></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"] = `
|
|
<form>
|
|
<field name="display_name"/>
|
|
<footer>
|
|
<button string="Create" type="object" class="infooter"/>
|
|
</footer>
|
|
</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"] = `
|
|
<form>
|
|
<button name="method" string="Call method" type="object" confirm="Are you sure?"/>
|
|
</form>`;
|
|
serverData.views["partner,1000,form"] = `<form>Another action</form>`;
|
|
|
|
const mockRPC = (route, args) => {
|
|
if (args.method === "method") {
|
|
return Promise.resolve({
|
|
id: 1000,
|
|
name: "Another window action",
|
|
res_model: "partner",
|
|
target: "new",
|
|
type: "ir.actions.act_window",
|
|
views: [[1000, "form"]],
|
|
});
|
|
}
|
|
};
|
|
const webClient = await createWebClient({ serverData, mockRPC });
|
|
|
|
await doAction(webClient, 999);
|
|
|
|
assert.containsOnce(document.body, ".modal button[name=method]");
|
|
|
|
await testUtils.dom.click($(".modal button[name=method]"));
|
|
|
|
assert.containsN(document.body, ".modal", 2);
|
|
assert.strictEqual($(".modal:last .modal-body").text(), "Are you sure?");
|
|
|
|
await testUtils.dom.click($(".modal:last .modal-footer .btn-primary"));
|
|
// needs two renderings to close the ConfirmationDialog:
|
|
// - 1 to open the next dialog (the action in target="new")
|
|
// - 1 to close the ConfirmationDialog, once the next action is executed
|
|
await nextTick();
|
|
assert.containsOnce(document.body, ".modal");
|
|
assert.strictEqual(
|
|
target.querySelector(".modal main .o_content").innerText.trim(),
|
|
"Another action"
|
|
);
|
|
}
|
|
);
|
|
|
|
QUnit.test('actions in target="new" do not update page title', async function (assert) {
|
|
const mockedTitleService = {
|
|
start() {
|
|
return {
|
|
setParts({ action }) {
|
|
if (action) {
|
|
assert.step(action);
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|
|
registry.category("services").add("title", mockedTitleService);
|
|
const webClient = await createWebClient({ serverData });
|
|
|
|
// sanity check: execute an action in target="current"
|
|
await doAction(webClient, 1);
|
|
assert.verifySteps(["Partners Action 1"]);
|
|
|
|
// execute an action in target="new"
|
|
await doAction(webClient, 5);
|
|
assert.verifySteps([]);
|
|
});
|
|
|
|
QUnit.test("do not commit a dialog in error", async (assert) => {
|
|
assert.expect(6);
|
|
|
|
const handler = (ev) => {
|
|
// need to preventDefault to remove error from console (so python test pass)
|
|
ev.preventDefault();
|
|
};
|
|
window.addEventListener("unhandledrejection", handler);
|
|
registerCleanup(() => window.removeEventListener("unhandledrejection", handler));
|
|
|
|
patchWithCleanup(QUnit, {
|
|
onUnhandledRejection: () => {},
|
|
});
|
|
|
|
class ErrorClientAction extends Component {
|
|
setup() {
|
|
throw new Error("my error");
|
|
}
|
|
}
|
|
ErrorClientAction.template = xml`<div/>`;
|
|
registry.category("actions").add("failing", ErrorClientAction);
|
|
|
|
class ClientActionTargetNew extends Component {}
|
|
ClientActionTargetNew.template = xml`<div class="my_action_new" />`;
|
|
registry.category("actions").add("clientActionNew", ClientActionTargetNew);
|
|
|
|
class ClientAction extends Component {
|
|
setup() {
|
|
this.action = useService("action");
|
|
}
|
|
async onClick() {
|
|
try {
|
|
await this.action.doAction(
|
|
{ type: "ir.actions.client", tag: "failing", target: "new" },
|
|
{ onClose: () => assert.step("failing dialog closed") }
|
|
);
|
|
} catch (e) {
|
|
assert.strictEqual(e.cause.message, "my error");
|
|
}
|
|
}
|
|
}
|
|
ClientAction.template = xml`
|
|
<div class="my_action" t-on-click="onClick">
|
|
My Action
|
|
</div>`;
|
|
registry.category("actions").add("clientAction", ClientAction);
|
|
|
|
const errorDialogOpened = makeDeferred();
|
|
patchWithCleanup(ClientErrorDialog.prototype, {
|
|
setup() {
|
|
this._super(...arguments);
|
|
onMounted(() => errorDialogOpened.resolve());
|
|
},
|
|
});
|
|
|
|
registry.category("services").add("error", errorService);
|
|
const webClient = await createWebClient({});
|
|
|
|
await doAction(webClient, { type: "ir.actions.client", tag: "clientAction" });
|
|
await click(target, ".my_action");
|
|
await errorDialogOpened;
|
|
|
|
assert.containsOnce(target, ".modal");
|
|
await click(target, ".modal-body button.btn-link");
|
|
assert.ok(
|
|
target.querySelector(".modal-body .o_error_detail").textContent.includes("my error")
|
|
);
|
|
|
|
await click(target, ".modal-footer button");
|
|
assert.containsNone(target, ".modal");
|
|
|
|
await doAction(webClient, {
|
|
type: "ir.actions.client",
|
|
tag: "clientActionNew",
|
|
target: "new",
|
|
});
|
|
assert.containsOnce(target, ".modal .my_action_new");
|
|
|
|
assert.verifySteps([]);
|
|
});
|
|
|
|
QUnit.test('breadcrumbs of actions in target="new"', async function (assert) {
|
|
const webClient = await createWebClient({ serverData });
|
|
|
|
// execute an action in target="current"
|
|
await doAction(webClient, 1);
|
|
assert.deepEqual(
|
|
[...target.querySelectorAll(".breadcrumb-item")].map((i) => i.innerText),
|
|
["Partners Action 1"]
|
|
);
|
|
|
|
// execute an action in target="new" and a list view (s.t. there is a control panel)
|
|
await doAction(webClient, {
|
|
xml_id: "action_5",
|
|
name: "Create a Partner",
|
|
res_model: "partner",
|
|
target: "new",
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "list"]],
|
|
});
|
|
assert.containsNone(target, ".modal .breadcrumb");
|
|
});
|
|
|
|
QUnit.test('call switchView in an action in target="new"', async function (assert) {
|
|
const webClient = await createWebClient({ serverData });
|
|
|
|
// execute an action in target="current"
|
|
await doAction(webClient, 4);
|
|
assert.containsOnce(target, ".o_kanban_view");
|
|
|
|
// execute an action in target="new" and a list view (s.t. we can call switchView)
|
|
await doAction(webClient, {
|
|
xml_id: "action_5",
|
|
name: "Create a Partner",
|
|
res_model: "partner",
|
|
target: "new",
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "list"]],
|
|
});
|
|
assert.containsOnce(target, ".modal .o_list_view");
|
|
assert.containsOnce(target, ".o_kanban_view");
|
|
|
|
// click on a record in the dialog -> should do nothing as we can't switch view
|
|
// in the dialog, and we don't want to switch view behind the dialog
|
|
await click(target.querySelector(".modal .o_data_row .o_data_cell"));
|
|
assert.containsOnce(target, ".modal .o_list_view");
|
|
assert.containsOnce(target, ".o_kanban_view");
|
|
});
|
|
|
|
QUnit.test("action with 'dialog_size' key in context", async function (assert) {
|
|
const action = {
|
|
name: "Some Action",
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
target: "new",
|
|
views: [[false, "form"]],
|
|
};
|
|
const webClient = await createWebClient({ serverData });
|
|
|
|
await doAction(webClient, action);
|
|
assert.hasClass(target.querySelector(".o_dialog .modal-dialog"), "modal-lg");
|
|
|
|
await doAction(webClient, { ...action, context: { dialog_size: "small" } });
|
|
assert.hasClass(target.querySelector(".o_dialog .modal-dialog"), "modal-sm");
|
|
|
|
await doAction(webClient, { ...action, context: { dialog_size: "medium" } });
|
|
assert.hasClass(target.querySelector(".o_dialog .modal-dialog"), "modal-md");
|
|
|
|
await doAction(webClient, { ...action, context: { dialog_size: "large" } });
|
|
assert.hasClass(target.querySelector(".o_dialog .modal-dialog"), "modal-lg");
|
|
|
|
await doAction(webClient, { ...action, context: { dialog_size: "extra-large" } });
|
|
assert.hasClass(target.querySelector(".o_dialog .modal-dialog"), "modal-xl");
|
|
});
|
|
|
|
QUnit.test('click on record in list view action in target="new"', async function (assert) {
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 1001);
|
|
await doAction(webClient, {
|
|
name: "Favorite Ponies",
|
|
res_model: "pony",
|
|
type: "ir.actions.act_window",
|
|
target: "new",
|
|
views: [[false, "list"], [false, "form"]],
|
|
});
|
|
|
|
// The list view has been opened in a dialog
|
|
assert.containsOnce(target, ".o_dialog .modal-dialog .o_list_view");
|
|
|
|
// click on a record in the dialog -> should do nothing as we can't switch view in the dialog
|
|
await click(target.querySelector(".modal .o_data_row .o_data_cell"));
|
|
assert.containsOnce(target, ".o_dialog .modal-dialog .o_list_view");
|
|
assert.containsNone(target, ".o_form_view");
|
|
});
|
|
|
|
QUnit.module('Actions in target="fullscreen"');
|
|
|
|
QUnit.test(
|
|
'correctly execute act_window actions in target="fullscreen"',
|
|
async function (assert) {
|
|
serverData.actions[1].target = "fullscreen";
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 1);
|
|
await nextTick(); // wait for the webclient template to be re-rendered
|
|
assert.containsOnce(target, ".o_control_panel", "should have rendered a control panel");
|
|
assert.containsOnce(target, ".o_kanban_view", "should have rendered a kanban view");
|
|
assert.containsNone(target, ".o_main_navbar");
|
|
}
|
|
);
|
|
|
|
QUnit.test('fullscreen on action change: back to a "current" action', async function (assert) {
|
|
serverData.actions[1].target = "fullscreen";
|
|
serverData.views[
|
|
"partner,false,form"
|
|
] = `<form><button name="1" type="action" class="oe_stat_button" /></form>`;
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 6);
|
|
assert.containsOnce(target, ".o_main_navbar");
|
|
await click(target.querySelector("button[name='1']"));
|
|
await nextTick(); // wait for the webclient template to be re-rendered
|
|
assert.containsNone(target, ".o_main_navbar");
|
|
await click(target.querySelector(".breadcrumb li a"));
|
|
await nextTick(); // wait for the webclient template to be re-rendered
|
|
assert.containsOnce(target, ".o_main_navbar");
|
|
});
|
|
|
|
QUnit.test('fullscreen on action change: all "fullscreen" actions', async function (assert) {
|
|
serverData.actions[6].target = "fullscreen";
|
|
serverData.views[
|
|
"partner,false,form"
|
|
] = `<form><button name="1" type="action" class="oe_stat_button" /></form>`;
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 6);
|
|
assert.isNotVisible(target.querySelector(".o_main_navbar"));
|
|
await click(target.querySelector("button[name='1']"));
|
|
assert.isNotVisible(target.querySelector(".o_main_navbar"));
|
|
await click(target.querySelector(".breadcrumb li a"));
|
|
assert.isNotVisible(target.querySelector(".o_main_navbar"));
|
|
});
|
|
|
|
QUnit.test(
|
|
'fullscreen on action change: back to another "current" action',
|
|
async function (assert) {
|
|
serverData.menus = {
|
|
root: { id: "root", children: [1], name: "root", appID: "root" },
|
|
1: { id: 1, children: [], name: "MAIN APP", appID: 1, actionID: 6 },
|
|
};
|
|
serverData.actions[1].target = "fullscreen";
|
|
serverData.views["partner,false,form"] =
|
|
'<form><button name="24" type="action" class="oe_stat_button"/></form>';
|
|
await createWebClient({ serverData });
|
|
await nextTick(); // wait for the load state (default app)
|
|
assert.containsOnce(target, "nav .o_menu_brand");
|
|
assert.strictEqual(target.querySelector("nav .o_menu_brand").innerText, "MAIN APP");
|
|
await click(target.querySelector("button[name='24']"));
|
|
await nextTick(); // wait for the webclient template to be re-rendered
|
|
assert.containsOnce(target, "nav .o_menu_brand");
|
|
await click(target.querySelector("button[name='1']"));
|
|
await nextTick(); // wait for the webclient template to be re-rendered
|
|
assert.containsNone(target, "nav.o_main_navbar");
|
|
await click(target.querySelectorAll(".breadcrumb li a")[1]);
|
|
await nextTick(); // wait for the webclient template to be re-rendered
|
|
assert.containsOnce(target, "nav .o_menu_brand");
|
|
assert.strictEqual(target.querySelector("nav .o_menu_brand").innerText, "MAIN APP");
|
|
}
|
|
);
|
|
|
|
QUnit.module('Actions in target="main"');
|
|
|
|
QUnit.test('can execute act_window actions in target="main"', async function (assert) {
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 1);
|
|
|
|
assert.containsOnce(target, ".o_kanban_view");
|
|
assert.containsOnce(target, ".breadcrumb-item");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Partners Action 1"
|
|
);
|
|
|
|
await doAction(webClient, {
|
|
name: "Another Partner Action",
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "list"]],
|
|
target: "main",
|
|
});
|
|
|
|
assert.containsOnce(target, ".o_list_view");
|
|
assert.containsOnce(target, ".breadcrumb-item");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Another Partner Action"
|
|
);
|
|
});
|
|
|
|
QUnit.test('can switch view in an action in target="main"', async function (assert) {
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, {
|
|
name: "Partner Action",
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
views: [
|
|
[false, "list"],
|
|
[false, "form"],
|
|
],
|
|
target: "main",
|
|
});
|
|
|
|
assert.containsOnce(target, ".o_list_view");
|
|
assert.containsOnce(target, ".breadcrumb-item");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Partner Action"
|
|
);
|
|
|
|
// open first record
|
|
await click(target.querySelector(".o_data_row .o_data_cell"));
|
|
|
|
assert.containsOnce(target, ".o_form_view");
|
|
assert.containsN(target, ".breadcrumb-item", 2);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Partner ActionFirst record"
|
|
);
|
|
});
|
|
|
|
QUnit.test('can restore an action in target="main"', async function (assert) {
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, {
|
|
name: "Partner Action",
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
views: [
|
|
[false, "list"],
|
|
[false, "form"],
|
|
],
|
|
target: "main",
|
|
});
|
|
|
|
assert.containsOnce(target, ".o_list_view");
|
|
assert.containsOnce(target, ".breadcrumb-item");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Partner Action"
|
|
);
|
|
|
|
// open first record
|
|
await click(target.querySelector(".o_data_row .o_data_cell"));
|
|
assert.containsOnce(target, ".o_form_view");
|
|
assert.containsN(target, ".breadcrumb-item", 2);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Partner ActionFirst record"
|
|
);
|
|
|
|
await doAction(webClient, 1);
|
|
assert.containsOnce(target, ".o_kanban_view");
|
|
assert.containsN(target, ".breadcrumb-item", 3);
|
|
|
|
// go back to form view
|
|
await click(target.querySelectorAll(".breadcrumb-item")[1]);
|
|
assert.containsOnce(target, ".o_form_view");
|
|
assert.containsN(target, ".breadcrumb-item", 2);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_control_panel .breadcrumb").textContent,
|
|
"Partner ActionFirst record"
|
|
);
|
|
});
|
|
});
|