Files
odoo_source/addons/mail/static/tests/helpers/mock_server.js
T
Hiral Bhavsar 983d098794 [IMP] mail: adapt activity qunit test suite
The activity view has been refactored and improved so the qunit test
suite needed to be adapted.

More tests have also been added to test new features (progressbar,
schedule an activity, etc.) and the method 'get_activity' has been
correctly mocked (the result was previously hardcoded).

Task 1894990
2019-05-03 10:19:40 +00:00

317 lines
11 KiB
JavaScript

odoo.define('mail.MockServer', function (require) {
"use strict";
var MockServer = require('web.MockServer');
MockServer.include({
/**
* Param 'data' may have a key 'initMessaging' which contains
* a partial overwrite of the result from mockInitMessaging.
*
* Note: we must delete this key, so that this is not
* handled as a model definition.
*
* @override
* @param {Object} [data.initMessaging] init messaging data
* @param {Widget} [options.widget] mocked widget (use to call services)
*/
init: function (data, options) {
if (data && data.initMessaging) {
this.initMessagingData = data.initMessaging;
delete data.initMessaging;
}
this._widget = options.widget;
this._super.apply(this, arguments);
},
/**
* Simulate the '/mail.channel/channel_fetch_preview' route
*
* @private
* @return {Object[]} list of channels previews
*/
_mockChannelFetchPreview: function (args) {
var self = this;
var ids = args.args[0]; // list of channel IDs to fetch preview
var model = args.model;
var channels = this._getRecords(model, [['id', 'in', ids]]);
var previews = _.map(channels, function (channel) {
var channelMessages = _.filter(self.data['mail.message'].records, function (message) {
return _.contains(message.channel_ids, channel.id);
});
var lastMessage = _.max(channelMessages, function (message) {
return message.id;
});
channel.last_message = lastMessage;
return channel;
});
return previews;
},
/**
* Simulate the 'get_activity_method' on 'mail.activity'
*
* @private
* @return {Object}
*/
_mockGetActivityData: function (args) {
var self = this;
var domain = args.kwargs.domain;
var model = args.kwargs.res_model;
var records = this._getRecords(model, domain);
var activityTypes = this._getRecords('mail.activity.type', []);
var activityIds = _.pluck(records, 'activity_ids').flat();
var groupedActivities = {};
var resIdToDeadline = {};
var groups = self._mockReadGroup('mail.activity', {
domain: [['id', 'in', activityIds]],
fields: ['res_id', 'activity_type_id', 'ids:array_agg(id)', 'date_deadline:min(date_deadline)'],
groupby: ['res_id', 'activity_type_id'],
lazy: false,
});
groups.forEach(function (group) {
// mockReadGroup doesn't correctly return all asked fields
var activites = self._getRecords('mail.activity', group.__domain);
group.activity_type_id = group.activity_type_id[0];
var minDate;
activites.forEach(function (activity) {
if (!minDate || moment(activity.date_deadline) < moment(minDate)) {
minDate = activity.date_deadline;
}
});
group.date_deadline = minDate;
resIdToDeadline[group.res_id] = minDate;
var state;
if (group.date_deadline === moment().format("YYYY-MM-DD")) {
state = 'today';
} else if (moment(group.date_deadline) > moment()) {
state = 'planned';
} else {
state = 'overdue';
}
if (!groupedActivities[group.res_id]) {
groupedActivities[group.res_id] = {};
}
groupedActivities[group.res_id][group.activity_type_id] = {
count: group.__count,
state: state,
o_closest_deadline: group.date_deadline,
ids: _.pluck(activites, 'id'),
};
});
return {
activity_types: activityTypes.map(function (type) {
var mailTemplates = [];
if (type.mail_template_ids) {
mailTemplates = type.mail_template_ids.map(function (id) {
var template = _.findWhere(self.data['mail.template'].records, {id: id});
return {
id: id,
name: template.name,
};
});
}
return [type.id, type.display_name, mailTemplates];
}),
activity_res_ids: _.sortBy(_.pluck(records, 'id'), function (id) {
return moment(resIdToDeadline[id]);
}),
grouped_activities: groupedActivities,
};
},
/**
* Simulate the '/mail/init_messaging' route
*
* @private
* @return {Object}
*/
_mockInitMessaging: function () {
return _.defaults(this.initMessagingData || {}, {
'needaction_inbox_counter': 0,
'starred_counter': 0,
'channel_slots': [],
'commands': [],
'mention_partner_suggestions': [],
'shortcodes': [],
'menu_id': false,
'mail_failures': [],
});
},
/**
* Simulate the 'message_fetch' Python method
*
* @private
* @return {Object[]}
*/
_mockMessageFetch: function (args) {
var domain = args.args[0];
var model = args.model;
var mod_channel_ids = args.kwargs.moderated_channel_ids;
var messages = this._getRecords(model, domain);
if (mod_channel_ids) {
var mod_messages = this._getRecords(
model,
[['model', '=', 'mail.channel'],
['res_id', 'in', mod_channel_ids],
['need_moderation', '=', true]]
);
messages = _.union(messages, mod_messages);
}
// sorted from highest ID to lowest ID (i.e. from youngest to oldest)
messages.sort(function (m1, m2) {
return m1.id < m2.id ? 1 : -1;
});
// pick at most 'limit' messages
return messages.slice(0, args.kwargs.limit);
},
/**
* Simulate the 'message_format' Python method
*
* @private
* @return {Object[]}
*/
_mockMessageFormat: function (args) {
var messageIDs = args.args[0];
var domain = [['id', 'in', messageIDs]];
var model = args.model;
var messages = this._getRecords(model, domain);
// sorted from highest ID to lowest ID (i.e. from youngest to oldest)
messages.sort(function (m1, m2) {
return m1.id < m2.id ? 1 : -1;
});
return messages;
},
/**
* Simulate the 'moderate' Python method
*
* @private
*/
_mockModerate: function (args) {
var messageIDs = args.args[0];
var decision = args.args[1];
var model = this.data['mail.message'];
if (decision === 'reject' || decision === 'discard') {
model.records = _.reject(model.records, function (rec) {
return _.contains(messageIDs, rec.id);
});
// simulate notification back (deletion of rejected/discarded
// message in channel)
var dbName = undefined; // useless for tests
var notifData = {
message_ids: messageIDs,
type: "deletion",
};
var metaData = [dbName, 'res.partner'];
var notification = [metaData, notifData];
this._widget.call('bus_service', 'trigger', 'notification', [notification]);
} else if (decision === 'accept') {
// simulate notification back (new accepted message in channel)
var messages = _.filter(model.records, function (rec) {
return _.contains(messageIDs, rec.id);
});
var notifications = [];
_.each(messages, function (message) {
var dbName = undefined; // useless for tests
var messageData = message;
message.moderation_status = 'accepted';
var metaData = [dbName, 'mail.channel'];
var notification = [metaData, messageData];
notifications.push(notification);
});
this._widget.call('bus_service', 'trigger', 'notification', notifications);
}
},
/**
* Simulate the 'set_message_done' Python method, which turns provided
* needaction message to non-needaction (i.e. they are marked as read from
* from the Inbox mailbox). Also notify on the longpoll bus that the
* messages have been marked as read, so that UI is updated.
*
* @private
* @param {Object} args
*/
_mockSetMessageDone: function (args) {
var self = this;
var messageIDs = args.args[0];
_.each(messageIDs, function (messageID) {
var message = _.findWhere(self.data['mail.message'].records, {
id: messageID
});
if (message) {
message.needaction = false;
message.needaction_partner_ids = [];
}
});
var header = [null, 'res.partner'];
var data = { type: 'mark_as_read', message_ids: messageIDs };
var notifications = [[header, data]];
this._widget.call('bus_service', 'trigger', 'notification', notifications);
},
/**
* @override
*/
_performRpc: function (route, args) {
// routes
if (route === '/mail/init_messaging') {
return Promise.resolve(this._mockInitMessaging(args));
}
// methods
if (args.method === 'channel_fetch_listeners') {
return Promise.resolve([]);
}
if (args.method === 'channel_fetch_preview') {
return Promise.resolve(this._mockChannelFetchPreview(args));
}
if (args.method === 'channel_minimize') {
return Promise.resolve();
}
if (args.method === 'channel_seen') {
return Promise.resolve();
}
if (args.method === 'channel_fetched') {
return Promise.resolve();
}
if (args.method === 'get_activity_data') {
return Promise.resolve(this._mockGetActivityData(args));
}
if (args.method === 'message_fetch') {
return Promise.resolve(this._mockMessageFetch(args));
}
if (args.method === 'message_format') {
return Promise.resolve(this._mockMessageFormat(args));
}
if (args.method === 'activity_format') {
var res = this._mockRead(args.model, args.args, args.kwargs);
res = res.map(function(record) {
if (record.mail_template_ids) {
record.mail_template_ids = record.mail_template_ids.map(function(template_id) {
return {id:template_id, name:"template"+template_id};
});
}
return record;
});
return Promise.resolve(res);
}
if (args.method === 'set_message_done') {
return Promise.resolve(this._mockSetMessageDone(args));
}
if (args.method === 'moderate') {
return Promise.resolve(this._mockModerate(args));
}
if (args.method === 'notify_typing') {
return Promise.resolve();
}
if (args.method === 'set_message_done') {
return Promise.resolve();
}
return this._super(route, args);
},
});
});