[FIX] web: action_service: do not commit a dialog that has failed
Open a action in target new that you'll know will fail to open. Make sure you put an onClose callback when executing doAction. Open another action in target new, that will succeed. Before this commit, the onClose of the first dialog is executed, while it should not. Indeed, if the dialog fails, the whole business flow is invalid altogether and no more business operation (in the onClose) should be executed After this commit, the onClose callback of the failing dialog is not executed.
This commit is contained in:
@@ -472,6 +472,7 @@ function makeActionManager(env) {
|
||||
}).then(() => {
|
||||
dialogCloseProm = undefined;
|
||||
});
|
||||
dialog = nextDialog;
|
||||
} else {
|
||||
// LEGACY CODE COMPATIBILITY: remove when controllers will be written in owl
|
||||
// we determine here which actions no longer occur in the nextStack,
|
||||
@@ -529,6 +530,7 @@ function makeActionManager(env) {
|
||||
|
||||
ControllerComponent.Component = controller.Component;
|
||||
|
||||
let nextDialog = {};
|
||||
if (action.target === "new") {
|
||||
cleanDomFromBootstrap();
|
||||
const actionDialogProps = {
|
||||
@@ -556,7 +558,7 @@ function makeActionManager(env) {
|
||||
}
|
||||
},
|
||||
});
|
||||
dialog = {
|
||||
nextDialog = {
|
||||
remove: removeDialog,
|
||||
onClose: onClose || options.onClose,
|
||||
};
|
||||
|
||||
@@ -4,8 +4,17 @@ import testUtils from "web.test_utils";
|
||||
import core from "web.core";
|
||||
import AbstractAction from "web.AbstractAction";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { legacyExtraNextTick } from "../../helpers/utils";
|
||||
import {
|
||||
click,
|
||||
legacyExtraNextTick,
|
||||
patchWithCleanup,
|
||||
makeDeferred,
|
||||
} 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/service_hook";
|
||||
import { ClientErrorDialog } from "@web/core/errors/error_dialogs";
|
||||
|
||||
let serverData;
|
||||
|
||||
@@ -322,6 +331,86 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
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 owl.Component {
|
||||
setup() {
|
||||
throw new Error("my error");
|
||||
}
|
||||
}
|
||||
ErrorClientAction.template = owl.tags.xml`<div/>`;
|
||||
registry.category("actions").add("failing", ErrorClientAction);
|
||||
|
||||
class ClientActionTargetNew extends owl.Component {}
|
||||
ClientActionTargetNew.template = owl.tags.xml`<div class="my_action_new" />`;
|
||||
registry.category("actions").add("clientActionNew", ClientActionTargetNew);
|
||||
|
||||
class ClientAction extends owl.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.message, "my error");
|
||||
}
|
||||
}
|
||||
}
|
||||
ClientAction.template = owl.tags.xml`<div class="my_action" t-on-click="onClick" />`;
|
||||
registry.category("actions").add("clientAction", ClientAction);
|
||||
|
||||
const errorDialogOpened = makeDeferred();
|
||||
patchWithCleanup(ClientErrorDialog.prototype, {
|
||||
mounted() {
|
||||
this._super(...arguments);
|
||||
errorDialogOpened.resolve();
|
||||
},
|
||||
});
|
||||
|
||||
registry.category("services").add("error", errorService);
|
||||
const webClient = await createWebClient({});
|
||||
|
||||
await doAction(webClient, { type: "ir.actions.client", tag: "clientAction" });
|
||||
await click(webClient.el, ".my_action");
|
||||
await errorDialogOpened;
|
||||
|
||||
assert.containsOnce(webClient, ".modal");
|
||||
await click(webClient.el, ".modal-body button.btn-link");
|
||||
assert.ok(
|
||||
webClient.el
|
||||
.querySelector(".modal-body .o_error_detail")
|
||||
.textContent.includes("my error")
|
||||
);
|
||||
|
||||
await click(webClient.el, ".modal-footer button");
|
||||
assert.containsNone(webClient, ".modal");
|
||||
|
||||
await doAction(webClient, {
|
||||
type: "ir.actions.client",
|
||||
tag: "clientActionNew",
|
||||
target: "new",
|
||||
});
|
||||
assert.containsOnce(webClient, ".modal .my_action_new");
|
||||
|
||||
assert.verifySteps([]);
|
||||
});
|
||||
|
||||
QUnit.module('Actions in target="inline"');
|
||||
QUnit.test(
|
||||
'form views for actions in target="inline" open in edit mode',
|
||||
|
||||
Reference in New Issue
Block a user