[FIX] mail: prevent crash when chat system is not ready
When a chatter is created, appended, and destroyed before being ready, bad things could happen. This is because the code in start/other deferred was executed regardless if the widget was still alive. And, some mechanisms, such as _getBus, depends on the event system. If the widget is destroyed, it will be remove from the component tree and such functions will then return undefined. To protect agains those issues, we simply make sure that the deferred are only resolved when the widget is still alive.
This commit is contained in:
@@ -21,7 +21,7 @@ var ThreadField = AbstractField.extend(chat_mixin, {
|
||||
this.msgIDs = this.value.res_ids;
|
||||
},
|
||||
willStart: function () {
|
||||
return this._chatReady();
|
||||
return this.alive(this._chatReady());
|
||||
},
|
||||
start: function () {
|
||||
var self = this;
|
||||
@@ -43,7 +43,7 @@ var ThreadField = AbstractField.extend(chat_mixin, {
|
||||
var def1 = this.thread.appendTo(this.$el);
|
||||
var def2 = this._super.apply(this, arguments);
|
||||
|
||||
return $.when(def1, def2).then(function () {
|
||||
return this.alive($.when(def1, def2)).then(function () {
|
||||
// unwrap the thread to remove an unnecessary level on div
|
||||
self.setElement(self.thread.$el);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ var BasicComposer = Composers.BasicComposer;
|
||||
|
||||
var createAsyncView = testUtils.createAsyncView;
|
||||
var createView = testUtils.createView;
|
||||
var createAsyncView = testUtils.createAsyncView;
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
|
||||
@@ -944,5 +945,69 @@ QUnit.test('fieldmany2many tags email', function (assert) {
|
||||
$('.modal-footer .btn-primary').click();
|
||||
});
|
||||
|
||||
QUnit.test('does not render and crash when destroyed before chat system is ready', function (assert) {
|
||||
assert.expect(0);
|
||||
|
||||
var def = $.Deferred();
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<sheet>' +
|
||||
'<field name="foo"/>' +
|
||||
'</sheet>' +
|
||||
'<div class="oe_chatter">' +
|
||||
'<field name="message_follower_ids" widget="mail_followers"/>' +
|
||||
'<field name="message_ids" widget="mail_thread"/>' +
|
||||
'<field name="activity_ids" widget="mail_activity"/>' +
|
||||
'</div>' +
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/mail/read_followers') {
|
||||
return $.when({
|
||||
followers: [],
|
||||
subtypes: [],
|
||||
});
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
intercepts: {
|
||||
chat_manager_ready: function (event) {
|
||||
// we delay the return of the chat_manager ready event
|
||||
event.data.callback(def);
|
||||
},
|
||||
get_messages: function (event) {
|
||||
event.stopPropagation();
|
||||
event.data.callback($.when([{
|
||||
attachment_ids: [],
|
||||
body: "",
|
||||
date: moment("2016-12-20 09:35:40"),
|
||||
id: 34,
|
||||
res_id: 3,
|
||||
author_id: ["3", "Fu Ck Mil Grom"],
|
||||
}]));
|
||||
},
|
||||
get_bus: function (event) {
|
||||
event.stopPropagation();
|
||||
event.data.callback(new Bus());
|
||||
},
|
||||
get_session: function (event) {
|
||||
event.stopPropagation();
|
||||
event.data.callback({uid: 1});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
form.destroy();
|
||||
// here, the chat_manager system is ready, and the chatter can try to render
|
||||
// itself. We simply make sure here that no crashes occur (since the form
|
||||
// view is destroyed, all rpcs will be dropped, and many other mechanisms
|
||||
// relying on events will not work, such as _getBus)
|
||||
def.resolve();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user