diff --git a/addons/web/static/src/core/errors/error_handlers.js b/addons/web/static/src/core/errors/error_handlers.js index f0d63de995c..3a35daec50a 100644 --- a/addons/web/static/src/core/errors/error_handlers.js +++ b/addons/web/static/src/core/errors/error_handlers.js @@ -97,6 +97,12 @@ export function rpcErrorHandler(env, error, originalError) { ErrorComponent = errorDialogRegistry.get(exceptionName); } } + if (!ErrorComponent && originalError.data.context) { + const exceptionClass = originalError.data.context.exception_class; + if (errorDialogRegistry.contains(exceptionClass)) { + ErrorComponent = errorDialogRegistry.get(exceptionClass); + } + } env.services.dialog.add(ErrorComponent || RPCErrorDialog, { traceback: error.traceback, diff --git a/addons/web/static/src/core/network/rpc_service.js b/addons/web/static/src/core/network/rpc_service.js index 9ab20fc4f72..a7fbceef2d5 100644 --- a/addons/web/static/src/core/network/rpc_service.js +++ b/addons/web/static/src/core/network/rpc_service.js @@ -29,11 +29,8 @@ export function makeErrorFromResponse(reponse) { // Odoo returns error like this, in a error field instead of properly // using http error codes... const { code, data: errorData, message, type: subType } = reponse; - const { context: data_context, name: data_name } = errorData || {}; - const { exception_class } = data_context || {}; - const exception_class_name = exception_class || data_name; const error = new RPCError(); - error.exceptionName = exception_class_name; + error.exceptionName = errorData.name; error.subType = subType; error.data = errorData; error.message = message; diff --git a/addons/web/static/tests/core/errors/error_service_tests.js b/addons/web/static/tests/core/errors/error_service_tests.js index a0636dd2dc6..2b9d10c59e5 100644 --- a/addons/web/static/tests/core/errors/error_service_tests.js +++ b/addons/web/static/tests/core/errors/error_service_tests.js @@ -80,7 +80,7 @@ QUnit.test("handle RPC_ERROR of type='server' and no associated dialog class", a }); QUnit.test( - "handle RPC_ERROR of type='server' and associated custom dialog class", + "handle custom RPC_ERROR of type='server' and associated custom dialog class", async (assert) => { assert.expect(2); class CustomDialog extends Component {} @@ -89,17 +89,21 @@ QUnit.test( const error = new RPCError(); error.code = 701; error.message = "Some strange error occured"; - error.exceptionName = "strange_error"; + const errorData = { + context: { exception_class: "strange_error" }, + name: "strange_error", + }; + error.data = errorData; function addDialog(dialogClass, props) { assert.strictEqual(dialogClass, CustomDialog); assert.deepEqual(props, { name: "RPC_ERROR", type: "server", code: 701, - data: null, + data: errorData, subType: null, message: "Some strange error occured", - exceptionName: "strange_error", + exceptionName: null, traceback: error.stack, }); } @@ -111,6 +115,46 @@ QUnit.test( } ); +QUnit.test( + "handle normal RPC_ERROR of type='server' and associated custom dialog class", + async (assert) => { + assert.expect(2); + class CustomDialog extends Component {} + CustomDialog.template = tags.xml``; + CustomDialog.components = { RPCErrorDialog }; + class NormalDialog extends Component {} + NormalDialog.template = tags.xml``; + NormalDialog.components = { RPCErrorDialog }; + const error = new RPCError(); + error.code = 701; + error.message = "A normal error occured"; + const errorData = { + context: { exception_class: "strange_error" }, + }; + error.exceptionName = "normal_error"; + error.data = errorData; + function addDialog(dialogClass, props) { + assert.strictEqual(dialogClass, NormalDialog); + assert.deepEqual(props, { + name: "RPC_ERROR", + type: "server", + code: 701, + data: errorData, + subType: null, + message: "A normal error occured", + exceptionName: "normal_error", + traceback: error.stack, + }); + } + serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true }); + await makeTestEnv(); + errorDialogRegistry.add("strange_error", CustomDialog); + errorDialogRegistry.add("normal_error", NormalDialog); + const errorEvent = new PromiseRejectionEvent("error", { reason: error, promise: null }); + await unhandledRejectionCb(errorEvent); + } +); + QUnit.test("handle CONNECTION_LOST_ERROR", async (assert) => { patchWithCleanup(browser, { setTimeout: (callback, delay) => {