Odoo18-Base/addons/web/static/tests/webclient/actions/close_action_tests.js
2025-03-10 11:12:23 +07:00

231 lines
8.8 KiB
JavaScript

/** @odoo-module **/
import testUtils from "web.test_utils";
import { registerCleanup } from "../../helpers/cleanup";
import {
click,
getFixture,
legacyExtraNextTick,
nextTick,
patchWithCleanup,
} from "../../helpers/utils";
import { createWebClient, doAction, getActionManagerServerData } from "./../helpers";
import { registry } from "@web/core/registry";
import { formView } from "@web/views/form/form_view";
import { listView } from "../../../src/views/list/list_view";
let serverData;
let target;
QUnit.module("ActionManager", (hooks) => {
hooks.beforeEach(() => {
serverData = getActionManagerServerData();
target = getFixture();
});
QUnit.module('"ir.actions.act_window_close" actions');
QUnit.test("close the currently opened dialog", async function (assert) {
assert.expect(2);
const webClient = await createWebClient({ serverData });
// execute an action in target="new"
await doAction(webClient, 5);
assert.containsOnce(
document.body,
".o_technical_modal .o_form_view",
"should have rendered a form view in a modal"
);
// execute an 'ir.actions.act_window_close' action
await doAction(webClient, {
type: "ir.actions.act_window_close",
});
assert.containsNone(document.body, ".o_technical_modal", "should have closed the modal");
});
QUnit.test("close dialog by clicking on the header button", async function (assert) {
assert.expect(5);
const webClient = await createWebClient({ serverData });
// execute an action in target="new"
function onClose() {
assert.step("on_close");
}
await doAction(webClient, 5, { onClose });
assert.containsOnce(target, ".o_dialog_container .o_dialog");
await click(target.querySelector(".o_dialog_container .o_dialog .modal-header button"));
assert.containsNone(target, ".o_dialog_container .o_dialog");
assert.verifySteps(["on_close"]);
// execute an 'ir.actions.act_window_close' action
// should not call 'on_close' as it was already called.
await doAction(webClient, { type: "ir.actions.act_window_close" });
assert.verifySteps([]);
});
QUnit.test('execute "on_close" only if there is no dialog to close', async function (assert) {
assert.expect(3);
const webClient = await createWebClient({ serverData });
// execute an action in target="new"
await doAction(webClient, 5);
function onClose() {
assert.step("on_close");
}
const options = { onClose };
// execute an 'ir.actions.act_window_close' action
// should not call 'on_close' as there is a dialog to close
await doAction(webClient, { type: "ir.actions.act_window_close" }, options);
assert.verifySteps([]);
// execute again an 'ir.actions.act_window_close' action
// should call 'on_close' as there is no dialog to close
await doAction(webClient, { type: "ir.actions.act_window_close" }, options);
assert.verifySteps(["on_close"]);
});
QUnit.test("close action with provided infos", async function (assert) {
assert.expect(1);
const webClient = await createWebClient({ serverData });
const options = {
onClose: function (infos) {
assert.strictEqual(
infos,
"just for testing",
"should have the correct close infos"
);
},
};
await doAction(
webClient,
{
type: "ir.actions.act_window_close",
infos: "just for testing",
},
options
);
});
QUnit.test("history back calls on_close handler of dialog action", async function (assert) {
assert.expect(4);
let form;
patchWithCleanup(formView.Controller.prototype, {
setup() {
this._super(...arguments);
form = this;
},
});
const webClient = await createWebClient({ serverData });
function onClose() {
assert.step("on_close");
}
// open a new dialog form
await doAction(webClient, 5, { onClose });
assert.containsOnce(target, ".modal");
form.env.config.historyBack();
assert.verifySteps(["on_close"], "should have called the on_close handler");
await nextTick();
assert.containsNone(target, ".modal");
});
QUnit.test("history back called within on_close", async function (assert) {
assert.expect(7);
let list;
patchWithCleanup(listView.Controller.prototype, {
setup() {
this._super(...arguments);
list = this;
},
});
const webClient = await createWebClient({ serverData });
await doAction(webClient, 1);
assert.containsOnce(target, ".o_kanban_view");
await doAction(webClient, 3);
assert.containsOnce(target, ".o_list_view");
function onClose() {
list.env.config.historyBack();
assert.step("on_close");
}
// open a new dialog form
await doAction(webClient, 5, { onClose });
await click(target, ".modal-header button.btn-close");
await nextTick();
await legacyExtraNextTick();
assert.containsNone(target, ".modal");
assert.containsNone(target, ".o_list_view");
assert.containsOnce(target, ".o_kanban_view");
assert.verifySteps(["on_close"]);
});
QUnit.test(
"history back calls on_close handler of dialog action with 2 breadcrumbs",
async function (assert) {
assert.expect(7);
let list;
patchWithCleanup(listView.Controller.prototype, {
setup() {
this._super(...arguments);
list = this;
},
});
const webClient = await createWebClient({ serverData });
await doAction(webClient, 1); // kanban
await doAction(webClient, 3); // list
assert.containsOnce(target, ".o_list_view");
function onClose() {
assert.step("on_close");
}
// open a new dialog form
await doAction(webClient, 5, { onClose });
assert.containsOnce(target, ".modal");
assert.containsOnce(target, ".o_list_view");
list.env.config.historyBack();
assert.verifySteps(["on_close"], "should have called the on_close handler");
await nextTick();
await legacyExtraNextTick();
assert.containsOnce(target, ".o_list_view");
assert.containsNone(target, ".modal");
}
);
QUnit.test("web client is not deadlocked when a view crashes", async function (assert) {
assert.expect(6);
const handler = (ev) => {
assert.step("error");
// need to preventDefault to remove error from console (so python test pass)
ev.preventDefault();
};
// fake error service so that the odoo qunit handlers don't think that they need to handle the error
registry.category("services").add("error", { start: () => {} });
window.addEventListener("unhandledrejection", handler);
registerCleanup(() => window.removeEventListener("unhandledrejection", handler));
patchWithCleanup(QUnit, {
onUnhandledRejection: () => {},
});
const readOnFirstRecordDef = testUtils.makeTestPromise();
const mockRPC = (route, args) => {
if (args.method === "read" && args.args[0][0] === 1) {
return readOnFirstRecordDef;
}
};
const webClient = await createWebClient({ serverData, mockRPC });
await doAction(webClient, 3);
// open first record in form view. this will crash and will not
// display a form view
await testUtils.dom.click($(target).find(".o_list_view .o_data_cell:first"));
assert.verifySteps([]);
await legacyExtraNextTick();
readOnFirstRecordDef.reject(new Error("not working as intended"));
await nextTick();
assert.verifySteps(["error"]);
assert.containsOnce(target, ".o_list_view", "there should still be a list view in dom");
// open another record, the read will not crash
await testUtils.dom.click(
$(target).find(".o_list_view .o_data_row:eq(2) .o_data_cell:first")
);
await legacyExtraNextTick();
assert.containsNone(target, ".o_list_view", "there should not be a list view in dom");
assert.containsOnce(target, ".o_form_view", "there should be a form view in dom");
});
});