diff --git a/addons/web/static/src/js/core/mixins.js b/addons/web/static/src/js/core/mixins.js index ae513b0b506..fff2a013bb5 100644 --- a/addons/web/static/src/js/core/mixins.js +++ b/addons/web/static/src/js/core/mixins.js @@ -447,15 +447,17 @@ var ServicesMixin = { return result; }, /** - * Build a RPC query + * Builds and executes RPC query. Returns a deferred's promise resolved with + * the RPC result. * * @param {string} arg1 either a route or a model * @param {string} method if a model is given, this argument is a method - * @returns {RPCBuilder} + * @returns {Deferred's Promise} */ _rpc: function (params, options) { var query = rpc.buildQuery(params); - return this.call('ajax', 'rpc', query.route, query.params, options); + var def = this.call('ajax', 'rpc', query.route, query.params, options); + return def ? def.promise() : $.Deferred().promise(); }, loadFieldView: function (dataset, view_id, view_type, options) { return this.loadViews(dataset.model, dataset.get_context(), [[view_id, view_type]], options).then(function (result) { diff --git a/addons/web/static/test/core/widget_tests.js b/addons/web/static/test/core/widget_tests.js index c0a0012f931..8988002734b 100644 --- a/addons/web/static/test/core/widget_tests.js +++ b/addons/web/static/test/core/widget_tests.js @@ -377,6 +377,19 @@ QUnit.module('core', {}, function () { done(); }); }); + + QUnit.test("calling _rpc on destroyed widgets", function (assert) { + assert.expect(1); + + var widget = new Widget(); + widget.destroy(); + widget._rpc({route: '/a/route'}).always(function () { + throw Error("Calling _rpc on a destroyed widget should return a " + + "deferred that is never resolved nor rejected"); + }); + assert.ok(true, + "there should be no crash when calling _rpc on a destroyed widget"); + }); }); }); \ No newline at end of file