[FIX] web: better handle error in actions
Before this commit, if there was a crash in a view or client action during an update (i.e. the action is already in the DOM, but an update triggers a re-rendering), the error was caught by the action service, it wasn't displayed to the user, and the action was re-rendered again (which could obviously result in the same error being thrown again and again). With this commit, we properly show the error, and we do not try to re-render the action. closes odoo/odoo#73507 Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
@@ -472,7 +472,23 @@ function makeActionManager(env) {
|
||||
throw error;
|
||||
} else {
|
||||
const lastCt = controllerStack[controllerStack.length - 1];
|
||||
const info = lastCt ? lastCt.__info__ : {};
|
||||
let info = {};
|
||||
if (lastCt) {
|
||||
if (lastCt.jsId === controller.jsId) {
|
||||
// the error occurred on the controller which is
|
||||
// already in the DOM, so simply show the error
|
||||
Promise.resolve().then(() => {
|
||||
throw error;
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
info = lastCt.__info__;
|
||||
// the error occurred while rendering a new controller,
|
||||
// so go back to the last non faulty controller
|
||||
// (the error will be shown anyway as the promise
|
||||
// has been rejected)
|
||||
}
|
||||
}
|
||||
env.bus.trigger("ACTION_MANAGER:UPDATE", info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { createWebClient, doAction, getActionManagerServerData } from "./../help
|
||||
const { Component, tags } = owl;
|
||||
|
||||
let serverData;
|
||||
const mainComponentRegistry = registry.category("main_components");
|
||||
const actionRegistry = registry.category("actions");
|
||||
|
||||
QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { createWebClient, doAction, getActionManagerServerData } from "./../helpers";
|
||||
import { registerCleanup } from "../../helpers/cleanup";
|
||||
import { click, patchWithCleanup } from "../../helpers/utils";
|
||||
import { errorService } from "@web/core/errors/error_service";
|
||||
|
||||
const { Component, tags } = owl;
|
||||
|
||||
@@ -15,7 +19,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.module("Error handling");
|
||||
|
||||
QUnit.test("error in a client action", async function (assert) {
|
||||
QUnit.test("error in a client action (at rendering)", async function (assert) {
|
||||
assert.expect(4);
|
||||
class Boom extends Component {}
|
||||
Boom.template = tags.xml`<div><t t-esc="a.b.c"/></div>`;
|
||||
@@ -33,4 +37,43 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
}
|
||||
assert.strictEqual(webClient.el.querySelector(".o_action_manager").innerHTML, contents);
|
||||
});
|
||||
|
||||
QUnit.test("error in a client action (after the first rendering)", async function (assert) {
|
||||
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: () => {},
|
||||
});
|
||||
|
||||
registry.category("services").add("error", errorService);
|
||||
|
||||
class Boom extends Component {
|
||||
setup() {
|
||||
this.boom = false;
|
||||
}
|
||||
onClick() {
|
||||
this.boom = true;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
Boom.template = tags.xml`
|
||||
<div>
|
||||
<t t-if="boom" t-esc="a.b.c"/>
|
||||
<button t-else="" class="my_button" t-on-click="onClick">Click Me</button>
|
||||
</div>`;
|
||||
actionRegistry.add("Boom", Boom);
|
||||
|
||||
const webClient = await createWebClient({ serverData });
|
||||
await doAction(webClient, "Boom");
|
||||
assert.containsOnce(webClient, ".my_button");
|
||||
|
||||
await click(document.querySelector(".my_button"));
|
||||
assert.containsOnce(webClient, ".my_button");
|
||||
assert.containsOnce(webClient, ".o_dialog_error");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user