[FIX] web: crash when clicking deleted records in breadcrumbs
Here is a way to reproduce the problematic situation: with CRM installed, go to Contacts, open one, clicks on its Opportunities stat button, open one in form view, click on the "Customer" field internal link to open again the contact in form view, delete the record, and finally click on the first occurence of the contact in the breadcrumbs. Before this commit, it crashed because we ended up in an error handler (formSaveErrorHandler) that doesn't deal with the fact that originalError could be falsy. This is handled by the legacyRejectPromiseHandler, but due to the low sequence of the faulty handler, this one was executed after. Same error would occur if you tried to open an url of a record that doesn't exist. This commit fixes the error handler sequences s.t. the crash no longer occurs. Issue reported in the feedback pad after migrating odoo.com to 16.0. closes odoo/odoo#110545 X-original-commit: 8e78efa3dda2484b34422a66d3963c7b20915036 Signed-off-by: Samuel Degueldre <sad@odoo.com> Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -18,7 +18,7 @@ import { registry } from "@web/core/registry";
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function legacyRejectPromiseHandler(env, error, originalError) {
|
||||
if (error.name === "UncaughtPromiseError") {
|
||||
if (error.name.startsWith("UncaughtPromiseError")) {
|
||||
const isLegitError = originalError && originalError instanceof Error;
|
||||
const isLegacyRPC = originalError && originalError.legacy;
|
||||
if (!isLegitError && !isLegacyRPC) {
|
||||
|
||||
@@ -44,4 +44,4 @@ function legacyRPCErrorHandler(env, error, originalError) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
errorHandlerRegistry.add("legacyRPCErrorHandler", legacyRPCErrorHandler, { sequence: 2 });
|
||||
errorHandlerRegistry.add("legacyRPCErrorHandler", legacyRPCErrorHandler, { sequence: 97 });
|
||||
|
||||
@@ -55,4 +55,4 @@ function formSaveErrorHandler(env, error, originalError) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
errorHandlerRegistry.add("formSaveErrorHandler", formSaveErrorHandler, { sequence: 1 });
|
||||
errorHandlerRegistry.add("formSaveErrorHandler", formSaveErrorHandler);
|
||||
|
||||
@@ -559,8 +559,8 @@ export function setupQUnit() {
|
||||
if (originalError instanceof Error) {
|
||||
originalError.errorEvent = ev;
|
||||
await completeUncaughtError(uncaughtError, originalError);
|
||||
originalError.stacktrace = uncaughtError.traceback;
|
||||
}
|
||||
originalError.stacktrace = uncaughtError.traceback;
|
||||
onError(originalError);
|
||||
});
|
||||
|
||||
@@ -577,8 +577,8 @@ export function setupQUnit() {
|
||||
if (originalError instanceof Error) {
|
||||
originalError.errorEvent = ev;
|
||||
await completeUncaughtError(uncaughtError, originalError);
|
||||
originalError.stack = uncaughtError.traceback;
|
||||
}
|
||||
originalError.stack = uncaughtError.traceback;
|
||||
onUnhandledRejection(originalError);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2631,4 +2631,77 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
assert.containsOnce(target, ".o_pivot_view .o_view_sample_data");
|
||||
});
|
||||
|
||||
QUnit.test("click on breadcrumb of a deleted record", async function (assert) {
|
||||
serviceRegistry.add("error", errorService);
|
||||
// In tests we catch unhandledrejection of promises rejected with something that isn't an
|
||||
// error (see tests/qunit.js). In this scenario, with the legacy basic_model, the promise
|
||||
// is rejected with undefined, so without the following lines, we can't reproduce the issue,
|
||||
// which was that the error handlers were executed in a wrong order, and one of them crashed.
|
||||
const windowUnhandledReject = window.onunhandledrejection;
|
||||
window.onunhandledrejection = null;
|
||||
registerCleanup(() => {
|
||||
window.onunhandledrejection = windowUnhandledReject;
|
||||
});
|
||||
|
||||
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: () => {},
|
||||
});
|
||||
|
||||
serverData.views["partner,false,form"] = `
|
||||
<form>
|
||||
<button type="action" name="3" string="Open Action 3" class="my_btn"/>
|
||||
</form>`;
|
||||
|
||||
const webClient = await createWebClient({ serverData });
|
||||
await doAction(webClient, 3);
|
||||
assert.containsOnce(target, ".o_list_view");
|
||||
|
||||
await click(target.querySelector(".o_data_row .o_data_cell"));
|
||||
assert.containsOnce(target, ".o_form_view");
|
||||
|
||||
await click(target.querySelector(".my_btn"));
|
||||
assert.containsOnce(target, ".o_list_view");
|
||||
|
||||
await click(target.querySelector(".o_data_row .o_data_cell"));
|
||||
assert.containsOnce(target, ".o_form_view");
|
||||
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".breadcrumb-item")), [
|
||||
"Partners",
|
||||
"First record",
|
||||
"Partners",
|
||||
"First record",
|
||||
]);
|
||||
|
||||
// open action menu and delete
|
||||
await cpHelpers.toggleActionMenu(target);
|
||||
await cpHelpers.toggleMenuItem(target, "Delete");
|
||||
assert.containsOnce(target, ".o_dialog");
|
||||
|
||||
// confirm
|
||||
await click(target.querySelector(".o_dialog .modal-footer .btn-primary"));
|
||||
assert.containsOnce(target, ".o_form_view");
|
||||
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".breadcrumb-item")), [
|
||||
"Partners",
|
||||
"First record",
|
||||
"Partners",
|
||||
"Second record",
|
||||
]);
|
||||
|
||||
// click on "First record" in breadcrumbs, which doesn't exist anymore
|
||||
await click(target.querySelectorAll(".breadcrumb-item a")[1]);
|
||||
await nextTick();
|
||||
assert.containsOnce(target, ".o_form_view");
|
||||
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".breadcrumb-item")), [
|
||||
"Partners",
|
||||
"First record",
|
||||
"Partners",
|
||||
"Second record",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user