3137 lines
121 KiB
JavaScript
3137 lines
121 KiB
JavaScript
odoo.define('mail.chatter_tests', function (require) {
|
|
"use strict";
|
|
|
|
var mailTestUtils = require('mail.testUtils');
|
|
|
|
var core = require('web.core');
|
|
var FormView = require('web.FormView');
|
|
var KanbanView = require('web.KanbanView');
|
|
var testUtils = require('web.test_utils');
|
|
var concurrency = require('web.concurrency');
|
|
|
|
var createView = testUtils.createView;
|
|
|
|
var Activity = require('mail.Activity');
|
|
var _t = core._t;
|
|
|
|
QUnit.module('mail', {}, function () {
|
|
|
|
QUnit.module('Chatter', {
|
|
beforeEach: function () {
|
|
// patch _.debounce and _.throttle to be fast and synchronous
|
|
this.underscoreDebounce = _.debounce;
|
|
this.underscoreThrottle = _.throttle;
|
|
_.debounce = _.identity;
|
|
_.throttle = _.identity;
|
|
|
|
this.services = mailTestUtils.getMailServices();
|
|
this.data = {
|
|
'res.partner': {
|
|
fields: {
|
|
im_status: {
|
|
string: "im_status",
|
|
type: "char",
|
|
}
|
|
},
|
|
records: [{
|
|
id: 1,
|
|
im_status: 'online',
|
|
}]
|
|
},
|
|
partner: {
|
|
fields: {
|
|
display_name: { string: "Displayed name", type: "char" },
|
|
foo: {string: "Foo", type: "char", default: "My little Foo Value"},
|
|
message_follower_ids: {
|
|
string: "Followers",
|
|
type: "one2many",
|
|
relation: 'mail.followers',
|
|
relation_field: "res_id",
|
|
},
|
|
message_ids: {
|
|
string: "messages",
|
|
type: "one2many",
|
|
relation: 'mail.message',
|
|
relation_field: "res_id",
|
|
},
|
|
activity_ids: {
|
|
string: 'Activities',
|
|
type: 'one2many',
|
|
relation: 'mail.activity',
|
|
relation_field: 'res_id',
|
|
},
|
|
activity_state: {
|
|
string: 'State',
|
|
type: 'selection',
|
|
selection: [['overdue', 'Overdue'], ['today', 'Today'], ['planned', 'Planned']],
|
|
},
|
|
message_attachment_count: {
|
|
string: 'Attachment count',
|
|
type: 'integer',
|
|
},
|
|
},
|
|
records: [{
|
|
id: 2,
|
|
message_attachment_count: 3,
|
|
display_name: "first partner",
|
|
foo: "HELLO",
|
|
message_follower_ids: [],
|
|
message_ids: [],
|
|
activity_ids: [],
|
|
}]
|
|
},
|
|
'mail.activity': {
|
|
fields: {
|
|
activity_type_id: { string: "Activity type", type: "many2one", relation: "mail.activity.type" },
|
|
create_uid: { string: "Created By", type: "many2one", relation: 'partner' },
|
|
can_write: { string: "Can write", type: "boolean" },
|
|
display_name: { string: "Display name", type: "char" },
|
|
date_deadline: { string: "Due Date", type: "date" },
|
|
user_id: { string: "Assigned to", type: "many2one", relation: 'partner' },
|
|
state: {
|
|
string: 'State',
|
|
type: 'selection',
|
|
selection: [['overdue', 'Overdue'], ['today', 'Today'], ['planned', 'Planned']],
|
|
},
|
|
activity_category: {
|
|
string: 'Category',
|
|
type: 'selection',
|
|
selection: [['default', 'Other'], ['upload_file', 'Upload File']],
|
|
},
|
|
note : { string: "Note", type: "char" },
|
|
},
|
|
},
|
|
'mail.activity.type': {
|
|
fields: {
|
|
name: { string: "Name", type: "char" },
|
|
category: {
|
|
string: 'Category',
|
|
type: 'selection',
|
|
selection: [['default', 'Other'], ['upload_file', 'Upload File']],
|
|
},
|
|
},
|
|
records: [
|
|
{ id: 1, name: "Type 1" },
|
|
{ id: 2, name: "Type 2" },
|
|
{ id: 3, name: "Type 3", category: 'upload_file' },
|
|
],
|
|
},
|
|
'mail.message': {
|
|
fields: {
|
|
attachment_ids: {
|
|
string: "Attachments",
|
|
type: 'many2many',
|
|
relation: 'ir.attachment',
|
|
default: [],
|
|
},
|
|
author_id: {
|
|
string: "Author",
|
|
relation: 'res.partner',
|
|
},
|
|
body: {
|
|
string: "Contents",
|
|
type: 'html',
|
|
},
|
|
date: {
|
|
string: "Date",
|
|
type: 'datetime',
|
|
},
|
|
is_note: {
|
|
string: "Note",
|
|
type: 'boolean',
|
|
},
|
|
is_discussion: {
|
|
string: "Discussion",
|
|
type: 'boolean',
|
|
},
|
|
is_notification: {
|
|
string: "Notification",
|
|
type: 'boolean',
|
|
},
|
|
is_starred: {
|
|
string: "Starred",
|
|
type: 'boolean',
|
|
},
|
|
model: {
|
|
string: "Related Document Model",
|
|
type: 'char',
|
|
},
|
|
res_id: {
|
|
string: "Related Document ID",
|
|
type: 'integer',
|
|
}
|
|
},
|
|
records: [],
|
|
},
|
|
'ir.attachment': {
|
|
fields:{
|
|
name:{type:'char', string:"attachment name", required:true},
|
|
res_model:{type:'char', string:"res model"},
|
|
res_id:{type:'integer', string:"res id"},
|
|
url:{type:'char', string:'url'},
|
|
type:{ type:'selection', selection:[['url',"URL"],['binary',"BINARY"]]},
|
|
mimetype:{type:'char', string:"mimetype"},
|
|
},
|
|
records:[
|
|
{id:1, type:'url', mimetype:'image/png', name:'filename.jpg',
|
|
res_id: 7, res_model: 'partner'},
|
|
{id:2, type:'binary', mimetype:"application/x-msdos-program",
|
|
name:"file2.txt", res_id: 7, res_model: 'partner'},
|
|
{id:3, type:'binary', mimetype:"application/x-msdos-program",
|
|
name:"file3.txt", res_id: 5, res_model: 'partner'},
|
|
],
|
|
},
|
|
};
|
|
},
|
|
afterEach: function () {
|
|
// unpatch _.debounce and _.throttle
|
|
_.debounce = this.underscoreDebounce;
|
|
_.throttle = this.underscoreThrottle;
|
|
}
|
|
});
|
|
|
|
QUnit.test('basic rendering', async function (assert) {
|
|
assert.expect(9);
|
|
|
|
var count = 0;
|
|
var unwanted_read_count = 0;
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
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>',
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/mail.followers/read') {
|
|
unwanted_read_count++;
|
|
}
|
|
if (route === '/mail/read_followers') {
|
|
count++;
|
|
return Promise.resolve({
|
|
followers: [],
|
|
subtypes: [],
|
|
});
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
res_id: 2,
|
|
});
|
|
assert.containsOnce(form, '.o_mail_activity', "there should be an activity widget");
|
|
assert.containsOnce(form, '.o_chatter_topbar .o_chatter_button_schedule_activity',
|
|
"there should be a 'Schedule an activity' button in the chatter's topbar");
|
|
assert.containsOnce(form, '.o_chatter_topbar .o_followers',
|
|
"there should be a followers widget, moved inside the chatter's topbar");
|
|
assert.containsOnce(form, '.o_chatter', "there should be a chatter widget");
|
|
assert.containsOnce(form, '.o_mail_thread');
|
|
assert.containsOnce(form, '.o_chatter_button_attachment', "should have one attachment button");
|
|
assert.containsNone(form, '.o_chatter_topbar .o_chatter_button_log_note',
|
|
"log note button should not be available");
|
|
|
|
await testUtils.form.clickEdit(form);
|
|
assert.strictEqual(count, 0, "should have done no read_followers rpc as there are no followers");
|
|
assert.strictEqual(unwanted_read_count, 0, "followers should only be fetched with read_followers route");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('basic rendering: message_attachment_count can be in view standalone', async function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="message_attachment_count" string="I\'m here"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_form_label').text(), "I'm here",
|
|
"The field message_attachment_count must be present according to the view's specs");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('basic rendering: message_attachment_count can be in view with chatter', async function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="message_attachment_count" string="I\'m here"/>' +
|
|
'</group>' +
|
|
'</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,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_form_label').text(), "I'm here",
|
|
"The field message_attachment_count must be present according to the view's specs");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('Activity Done keep feedback on blur', async function (assert) {
|
|
assert.expect(3);
|
|
var done = assert.async();
|
|
|
|
this.data['mail.activity'].records = [
|
|
{activity_type_id: 1, id: 1, can_write: true, user_id: 2, state: 'today', note: 'But I\'m talkin\' about Shaft'},
|
|
];
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
|
|
var shownDef = testUtils.makeTestPromise();
|
|
var hiddenDef = testUtils.makeTestPromise();
|
|
testUtils.mock.patch(Activity, {
|
|
_bindPopoverFocusout: function () {
|
|
this._super.apply(this, arguments);
|
|
shownDef.resolve();
|
|
},
|
|
});
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
res_id: 2,
|
|
arch:'<form string="Partners">' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
});
|
|
// sanity checks
|
|
var $activityEl = form.$('.o_mail_activity[name=activity_ids]');
|
|
assert.strictEqual($activityEl.find('.o_thread_message').length, 1,
|
|
'There should be one activity');
|
|
assert.strictEqual($activityEl.find('.o_thread_message .o_thread_message_note').text().trim(),
|
|
'But I\'m talkin\' about Shaft', 'The activity should have the right note');
|
|
|
|
var $popoverEl = $activityEl.find('.o_thread_message_tools .o_mark_as_done');
|
|
$popoverEl.on('hidden.bs.popover', hiddenDef.resolve.bind(hiddenDef));
|
|
|
|
// open popover
|
|
await testUtils.dom.click($popoverEl);
|
|
|
|
shownDef.then(function () {
|
|
// write a feedback and focusout
|
|
var $feedbackPopover = $($popoverEl.data('bs.popover').tip);
|
|
$feedbackPopover.find('#activity_feedback').val('John Shaft').focusout();
|
|
|
|
hiddenDef.then(async function () {
|
|
shownDef = testUtils.makeTestPromise();
|
|
|
|
// re-open popover
|
|
await testUtils.dom.click($popoverEl);
|
|
|
|
shownDef.then(function () {
|
|
var $feedbackPopover = $($popoverEl.data('bs.popover').tip);
|
|
assert.strictEqual($feedbackPopover.find('#activity_feedback').val(), 'John Shaft',
|
|
"feedback should have been kept");
|
|
|
|
form.destroy();
|
|
testUtils.mock.unpatch(Activity);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
QUnit.test('Activity Done by uploading a file', async function (assert) {
|
|
assert.expect(4);
|
|
|
|
// simulate (shortcut) the upload and trigger the event when the
|
|
// attachment is created serverside.
|
|
testUtils.mock.patch(Activity, {
|
|
_onMarkActivityDoneUploadFile: function (ev) {
|
|
var $markDoneBtn = $(ev.currentTarget);
|
|
var fileuploadID = $markDoneBtn.data('fileupload-id');
|
|
|
|
$(window).trigger(fileuploadID, [{
|
|
id:3,
|
|
type:'binary',
|
|
mimetype:"application/x-msdos-program",
|
|
name:"file2.txt",
|
|
res_id: 5,
|
|
res_model: 'partner'
|
|
}]);
|
|
},
|
|
});
|
|
|
|
// create the activity
|
|
this.data['mail.activity'].records = [{
|
|
activity_type_id: 3,
|
|
id: 1,
|
|
can_write: true,
|
|
user_id: 2,
|
|
state: 'today',
|
|
note: "But I'm talkin' about Shaft",
|
|
activity_category: 'upload_file'
|
|
}];
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
res_id: 2,
|
|
arch:'<form string="Partners">' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'action_feedback') {
|
|
var current_ids = this.data.partner.records[0].activity_ids;
|
|
var done_ids = args.args[0];
|
|
this.data.partner.records[0].activity_ids = _.difference(current_ids, done_ids);
|
|
this.data.partner.records[0].activity_state = false;
|
|
return Promise.resolve();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
var $activity = form.$('.o_mail_activity[name=activity_ids]');
|
|
assert.containsOnce($activity, '.o_thread_message', 'There should be one activity');
|
|
assert.containsOnce($activity, '.o_hidden_input_file', 'There should be one hidden file upload form');
|
|
assert.strictEqual($activity.find('.o_thread_message .o_thread_message_note').text().trim(),
|
|
'But I\'m talkin\' about Shaft', 'The activity should have the right note');
|
|
|
|
// click on "upload" button
|
|
var $uploadBtn = $activity.find('.o_mark_as_done_upload_file');
|
|
await testUtils.dom.click($uploadBtn);
|
|
|
|
assert.containsNone($activity, '.o_thread_message', 'The only activity should be marked as done');
|
|
|
|
testUtils.mock.unpatch(Activity);
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('attachmentBox basic rendering', async function (assert) {
|
|
assert.expect(19);
|
|
this.data.partner.records.push({
|
|
id: 7,
|
|
display_name: "attachment_test",
|
|
});
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 7,
|
|
mockRPC: function (route, args) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (args.method === 'read' && args.model === 'partner') {
|
|
return result.then(function (records) {
|
|
// here we force the attachment_count to 1 (which is correct
|
|
// actually), so that the attachment button is visible
|
|
// FIXME: this could be handled by an extension of mockRead
|
|
records[0].message_attachment_count = 1;
|
|
return records;
|
|
});
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
var $button = form.$('.o_chatter_button_attachment');
|
|
assert.strictEqual($button.length, 1, "should have one attachment button");
|
|
await testUtils.dom.click($button);
|
|
assert.containsOnce(form, '.o_mail_chatter_attachments',
|
|
"attachment widget should exist after a first click on the button");
|
|
assert.containsOnce(form, '.o_attachment_image', "there should be an image preview");
|
|
assert.containsOnce(form, '.o_attachments_previews', "there should be a list of previews");
|
|
assert.containsOnce(form, '.o_attachments_list', "there should be a list of non previewable attachments");
|
|
assert.containsOnce(form, '.o_upload_attachments_button', "there should be an 'Add Attachments' button");
|
|
assert.containsOnce(form, '.o_form_binary_form', "there should be a binary form");
|
|
|
|
assert.containsOnce(form, 'input[name="model"]', "there should be an model input");
|
|
var $modelInput = form.$('input[name="model"]');
|
|
assert.hasAttrValue($modelInput, 'value', 'partner');
|
|
assert.hasAttrValue($modelInput, 'type', 'hidden');
|
|
|
|
assert.containsOnce(form, 'input[name="model"]', "there should be an id input");
|
|
var $resIdInput = form.$('input[name="id"]');
|
|
assert.hasAttrValue($resIdInput, 'value', '7');
|
|
assert.hasAttrValue($resIdInput, 'type', 'hidden');
|
|
|
|
assert.strictEqual(form.$('.o_attachment_title').text(), 'filename.jpg',
|
|
"the image name should be correct");
|
|
// since there are two elements "Download name2"; one "name" and the other "txt" as text content, the following test
|
|
// asserts both at the same time.
|
|
assert.strictEqual(form.$('a[title = "Download file2.txt"]').text().trim(), 'file2.txttxt',
|
|
"the attachment name and the extension display should be correct");
|
|
assert.ok(form.$('.o_attachment_image').css('background-image').indexOf('/web/image/1/160x160/?crop=true') >= 0,
|
|
"the attachment image URL should be correct");
|
|
assert.hasAttrValue(form.$('.o_attachment_download').eq(0), 'href', '/web/content/1?download=true',
|
|
"the download URL of name1 must be correct");
|
|
assert.hasAttrValue(form.$('.o_attachment_download').eq(1), 'href', '/web/content/2?download=true',
|
|
"the download URL of name2 must be correct");
|
|
await testUtils.dom.click($button);
|
|
assert.containsNone(form, '.o_mail_chatter_attachments')
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter in create mode', async function (assert) {
|
|
assert.expect(9);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (route === "/mail/get_suggested_recipients") {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
assert.containsOnce(form, '.o_chatter',
|
|
"chatter should be displayed");
|
|
|
|
// entering create mode
|
|
await testUtils.form.clickCreate(form);
|
|
assert.hasClass(form.$el.find('.o_form_view'),'o_form_editable',
|
|
"we should be in create mode");
|
|
assert.containsOnce(form, '.o_chatter',
|
|
"chatter should still be displayed in create mode");
|
|
|
|
// topbar buttons disabled in create mode (e.g. 'send message')
|
|
assert.strictEqual(form.$('.o_chatter_topbar button:not(:disabled)').length, 0,
|
|
"button should be disabled in create mode");
|
|
|
|
// chatter containing a single message with 'Creating a record...'
|
|
assert.containsOnce(form, '.o_mail_thread',
|
|
"there should be a mail thread");
|
|
assert.containsOnce(form, '.o_thread_message',
|
|
"there should be a single thread message");
|
|
assert.strictEqual(form.$('.o_thread_message_content').text().trim(),
|
|
"Creating a new record...",
|
|
"the content of the message should be 'Creating a new record...'");
|
|
|
|
// getting out of create mode by saving
|
|
await testUtils.fields.editInput(form.$('.o_field_char'), 'coucou');
|
|
await testUtils.form.clickSave(form);
|
|
|
|
assert.containsOnce(form, '.o_chatter',
|
|
"chatter should still be displayed after saving from create mode");
|
|
|
|
// check if chatter buttons still work
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.containsOnce(form, '.o_thread_composer:visible',
|
|
"chatter should be opened");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter rendering inside the sheet', async function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'<notebook>' +
|
|
'<page>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</page>' +
|
|
'</notebook>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (route === "/mail/get_suggested_recipients") {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
assert.containsOnce(form, '.o_chatter',
|
|
"chatter should be displayed");
|
|
|
|
await testUtils.form.clickCreate(form);
|
|
assert.hasClass(form.$el.find('.o_form_view'),'o_form_editable',
|
|
"we should be in create mode");
|
|
|
|
assert.containsOnce(form, '.o_chatter',
|
|
"chatter should be displayed");
|
|
|
|
await testUtils.fields.editInput(form.$('.o_field_char'), 'coucou');
|
|
await testUtils.form.clickSave(form);
|
|
|
|
assert.containsOnce(form, '.o_chatter',
|
|
"chatter should be displayed");
|
|
|
|
// check if chatter buttons still work
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.containsOnce(form, '.o_thread_composer:visible',
|
|
"chatter should be opened");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('kanban activity widget with no activity', async function (assert) {
|
|
assert.expect(4);
|
|
|
|
var rpcCount = 0;
|
|
var kanban = await createView({
|
|
View: KanbanView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<kanban>' +
|
|
'<field name="activity_state"/>' +
|
|
'<templates><t t-name="kanban-box">' +
|
|
'<div><field name="activity_ids" widget="kanban_activity"/></div>' +
|
|
'</t></templates>' +
|
|
'</kanban>',
|
|
mockRPC: function (route, args) {
|
|
rpcCount++;
|
|
return this._super(route, args);
|
|
},
|
|
session: {uid: 2},
|
|
});
|
|
|
|
var $record = kanban.$('.o_kanban_record').first();
|
|
assert.ok($record.find('.o_mail_activity .o_activity_color_default').length,
|
|
"activity widget should have been rendered correctly");
|
|
assert.strictEqual(rpcCount, 1, '1 RPC (search_read) should have been done');
|
|
|
|
// click on the activity button
|
|
await testUtils.dom.click($record.find('.o_activity_btn'));
|
|
assert.strictEqual(rpcCount, 1, 'no RPC should have been done as there is no activity');
|
|
assert.strictEqual($record.find('.o_no_activity').length, 1, "should have no activity scheduled");
|
|
|
|
// fixme: it would be nice to be able to test the scheduling of a new activity, but not
|
|
// possible for now as we can't mock a fields_view_get (required by the do_action)
|
|
kanban.destroy();
|
|
});
|
|
|
|
QUnit.test('kanban activity widget with an activity', async function (assert) {
|
|
assert.expect(12);
|
|
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 1,
|
|
}];
|
|
var rpcCount = 0;
|
|
var kanban = await createView({
|
|
View: KanbanView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<kanban>' +
|
|
'<field name="activity_state"/>' +
|
|
'<templates><t t-name="kanban-box">' +
|
|
'<div><field name="activity_ids" widget="kanban_activity"/></div>' +
|
|
'</t></templates>' +
|
|
'</kanban>',
|
|
mockRPC: function (route, args) {
|
|
rpcCount++;
|
|
if (route === '/web/dataset/call_kw/mail.activity/action_feedback') {
|
|
var current_ids = this.data.partner.records[0].activity_ids;
|
|
var done_ids = args.args[0];
|
|
this.data.partner.records[0].activity_ids = _.difference(current_ids, done_ids);
|
|
this.data.partner.records[0].activity_state = false;
|
|
return Promise.resolve();
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
session: {uid:2},
|
|
});
|
|
|
|
var $record = kanban.$('.o_kanban_record').first();
|
|
assert.ok($record.find('.o_mail_activity .o_activity_color_today').length,
|
|
"activity widget should have been rendered correctly");
|
|
assert.strictEqual(rpcCount, 1, '1 RPC (search_read) should have been done');
|
|
|
|
// click on the activity button
|
|
await testUtils.dom.click($record.find('.o_activity_btn'));
|
|
assert.strictEqual(rpcCount, 2, 'a read should have been done to fetch the activity details');
|
|
assert.strictEqual($record.find('.o_activity_title').length, 1, "should have an activity scheduled");
|
|
var label = $record.find('.o_activity_log .o_activity_color_today');
|
|
assert.strictEqual(label.find('strong').text(), "Today", "should display the correct label");
|
|
assert.strictEqual(label.find('.badge-warning').text(), "1", "should display the correct count");
|
|
|
|
// click on the activity button to close the dropdown
|
|
await testUtils.dom.click($record.find('.o_activity_btn'));
|
|
assert.strictEqual(rpcCount, 2, 'no RPC should be done when closing the dropdown');
|
|
|
|
// click on the activity button to re-open dropdown
|
|
await testUtils.dom.click($record.find('.o_activity_btn'));
|
|
assert.strictEqual(rpcCount, 3, 'should have reloaded the activities');
|
|
|
|
// mark activity as done
|
|
await testUtils.dom.click($record.find('.o_mark_as_done'));
|
|
await testUtils.dom.click($record.find('.o_activity_popover_done'));
|
|
$record = kanban.$('.o_kanban_record').first(); // the record widget has been reset
|
|
assert.strictEqual(rpcCount, 5, 'should have done an RPC to mark activity as done, and a read');
|
|
assert.ok($record.find('.o_mail_activity .o_activity_color_default:not(.o_activity_color_today)').length,
|
|
"activity widget should have been updated correctly");
|
|
assert.strictEqual($record.find('.o_mail_activity.show').length, 1,
|
|
"dropdown should remain open when marking an activity as done");
|
|
assert.strictEqual($record.find('.o_no_activity').length, 1, "should have no activity scheduled");
|
|
|
|
kanban.destroy();
|
|
});
|
|
|
|
QUnit.test('kanban activity widget popover test', async function (assert) {
|
|
assert.expect(3);
|
|
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 1,
|
|
}];
|
|
var rpcCount = 0;
|
|
var kanban = await createView({
|
|
View: KanbanView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<kanban>' +
|
|
'<field name="activity_state"/>' +
|
|
'<templates><t t-name="kanban-box">' +
|
|
'<div><field name="activity_ids" widget="kanban_activity"/></div>' +
|
|
'</t></templates>' +
|
|
'</kanban>',
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/mail.activity/action_feedback_schedule_next') {
|
|
rpcCount++;
|
|
|
|
var current_ids = this.data.partner.records[0].activity_ids;
|
|
var done_ids = args.args[0];
|
|
this.data.partner.records[0].activity_ids = _.difference(current_ids, done_ids);
|
|
this.data.partner.records[0].activity_state = false;
|
|
return Promise.resolve();
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
var $record = kanban.$('.o_kanban_record').first();
|
|
|
|
await testUtils.dom.click($record.find('.o_activity_btn'));
|
|
|
|
// Click on button and see popover no RPC call
|
|
await testUtils.dom.click($record.find('.o_mark_as_done'));
|
|
assert.equal(rpcCount, 0, "");
|
|
// Click on discard no RPC call
|
|
await testUtils.dom.click($record.find('.o_activity_popover_discard'));
|
|
assert.equal(rpcCount, 0, "");
|
|
// Click on button and then on done and schedule next
|
|
// RPC call
|
|
await testUtils.dom.click($record.find('.o_activity_popover_done_next'));
|
|
assert.equal(rpcCount, 1, "");
|
|
|
|
kanban.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: post, receive and star messages', async function (assert) {
|
|
assert.expect(26);
|
|
|
|
this.data.partner.records[0].message_ids = [1];
|
|
this.data['mail.message'].records = [{
|
|
author_id: ["1", "John Doe"],
|
|
body: "A message",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 1,
|
|
is_note: false,
|
|
is_discussion: true,
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
}];
|
|
|
|
var getSuggestionsDef = testUtils.makeTestPromise();
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'get_mention_suggestions') {
|
|
getSuggestionsDef.resolve();
|
|
return Promise.resolve([[{email: "test@odoo.com", id: 1, name: "Test User"}], []]);
|
|
}
|
|
if (args.method === 'message_post') {
|
|
var lastMessageData = _.max(this.data['mail.message'].records, function (messageData) {
|
|
return messageData.id;
|
|
});
|
|
var messageID = lastMessageData.id + 1;
|
|
this.data['mail.message'].records.push({
|
|
attachment_ids: args.kwargs.attachment_ids,
|
|
author_id: ["42", "Me"],
|
|
body: args.kwargs.body,
|
|
date: "2016-12-20 10:35:40",
|
|
id: messageID,
|
|
is_note: args.kwargs.subtype === 'mail.mt_note',
|
|
is_discussion: args.kwargs.subtype === 'mail.mt_comment',
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
return Promise.resolve(messageID);
|
|
}
|
|
if (args.method === 'toggle_message_starred') {
|
|
assert.ok(_.contains(args.args[0], 2),
|
|
"toggle_star_status should have been triggered for message 2 (twice)");
|
|
var messageData = _.findWhere(
|
|
this.data['mail.message'].records,
|
|
{ id: args.args[0][0] }
|
|
);
|
|
messageData.is_starred = !messageData.is_starred;
|
|
// simulate notification received by mail_service from longpoll
|
|
var data = {
|
|
info: false,
|
|
message_ids: [messageData.id],
|
|
starred: messageData.is_starred,
|
|
type: 'toggle_star',
|
|
};
|
|
var notification = [[false, 'res.partner'], data];
|
|
form.call('bus_service', 'trigger', 'notification', [notification]);
|
|
return Promise.resolve();
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
session: {},
|
|
});
|
|
|
|
assert.ok(form.$('.o_chatter_topbar .o_chatter_button_log_note').length,
|
|
"log note button should be available");
|
|
assert.containsOnce(form, '.o_thread_message', "thread should contain one message");
|
|
assert.ok(form.$('.o_thread_message:first().o_mail_discussion').length,
|
|
"the message should be a discussion");
|
|
assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('A message') >= 0,
|
|
"the message's body should be correct");
|
|
assert.ok(form.$('.o_thread_message:first() .o_mail_info').text().indexOf('John Doe') >= 0,
|
|
"the message's author should be correct");
|
|
|
|
// send a message
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.isVisible($('.oe_chatter .o_thread_composer'), "chatter should be opened");
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
assert.isNotVisible($('.oe_chatter .o_thread_composer'), "chatter should be closed");
|
|
assert.containsN(form, '.o_thread_message', 2, "thread should contain two messages");
|
|
assert.ok(form.$('.o_thread_message:first().o_mail_discussion').length,
|
|
"the last message should be a discussion");
|
|
assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first message') >= 0,
|
|
"the message's body should be correct");
|
|
assert.ok(form.$('.o_thread_message:first() .o_mail_info').text().indexOf('Me') >= 0,
|
|
"the message's author should be correct");
|
|
|
|
// log a note
|
|
await testUtils.dom.click(form.$('.o_chatter_button_log_note'));
|
|
assert.isVisible($('.oe_chatter .o_thread_composer'), "chatter should be opened");
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first note");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
assert.isNotVisible($('.oe_chatter .o_thread_composer'), "chatter should be closed");
|
|
assert.containsN(form, '.o_thread_message', 3, "thread should contain three messages");
|
|
assert.ok(!form.$('.o_thread_message:first().o_mail_discussion').length,
|
|
"the last message should not be a discussion");
|
|
assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first note') >= 0,
|
|
"the message's body should be correct");
|
|
assert.ok(form.$('.o_thread_message:first() .o_mail_info').text().indexOf('Me') >= 0,
|
|
"the message's author should be correct");
|
|
|
|
// star message 2
|
|
assert.ok(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star.fa-star-o').length,
|
|
"message 2 should not be starred");
|
|
await testUtils.dom.click(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star'));
|
|
assert.ok(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star.fa-star').length,
|
|
"message 2 should be starred");
|
|
|
|
// unstar message 2
|
|
await testUtils.dom.click(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star'));
|
|
assert.ok(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star.fa-star-o').length,
|
|
"message 2 should not be starred");
|
|
|
|
// very basic test of mention
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
var $input = form.$('.oe_chatter .o_composer_text_field:first()');
|
|
$input.val('@');
|
|
// the cursor position must be set for the mention manager to detect that we are mentionning
|
|
$input[0].selectionStart = 1;
|
|
$input[0].selectionEnd = 1;
|
|
$input.trigger('keyup');
|
|
|
|
await testUtils.nextTick();
|
|
await getSuggestionsDef;
|
|
await testUtils.nextTick();
|
|
assert.containsOnce(form, '.o_mention_proposition:visible',
|
|
"there should be one mention suggestion");
|
|
assert.strictEqual(form.$('.o_mention_proposition').data('id'), 1,
|
|
"suggestion's id should be correct");
|
|
assert.strictEqual(form.$('.o_mention_proposition .o_mention_name').text(), 'Test User',
|
|
"suggestion should be displayed correctly");
|
|
assert.strictEqual(form.$('.o_mention_proposition .o_mention_info').text(), '(test@odoo.com)',
|
|
"suggestion should be displayed correctly");
|
|
//cleanup
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: post a message disable the send button', async function(assert) {
|
|
assert.expect(3);
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'message_post') {
|
|
assert.ok(form.$('.o_composer_button_send').prop("disabled"),
|
|
"Send button should be disabled when a message is being sent");
|
|
return Promise.resolve(57923);
|
|
}
|
|
if (args.method === 'message_format') {
|
|
return Promise.resolve([{
|
|
author_id: ["42", "Me"],
|
|
model: 'partner',
|
|
}]);
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.notOk(form.$('.o_composer_button_send').prop('disabled'),
|
|
"Send button should be enabled when posting a message");
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.notOk(form.$('.o_composer_button_send').prop('disabled'),
|
|
"Send button should be enabled when posting another message");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: post message failure keep message', async function(assert) {
|
|
assert.expect(4);
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'message_post') {
|
|
assert.ok(form.$('.o_composer_button_send').prop("disabled"),
|
|
"Send button should be disabled when a message is being sent");
|
|
// simulate failure
|
|
return Promise.reject();
|
|
|
|
}
|
|
if (args.method === 'message_format') {
|
|
return Promise.resolve([]);
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.notOk(form.$('.o_composer_button_send').prop('disabled'),
|
|
"Send button should be enabled initially");
|
|
await testUtils.fields.editInput(form.$('.oe_chatter .o_composer_text_field:first()'), "My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
assert.strictEqual(form.$('.o_composer_text_field').val(), "My first message",
|
|
"Should keep unsent message in the composer on failure");
|
|
assert.notOk(form.$('.o_composer_button_send').prop('disabled'),
|
|
"Send button should be re-enabled on message post failure");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: receive notif when document is open', async function (assert) {
|
|
assert.expect(2);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {
|
|
partner_id: 3,
|
|
},
|
|
});
|
|
|
|
var thread = form.call('mail_service', 'getDocumentThread', 'partner', 2);
|
|
assert.strictEqual(thread.getUnreadCounter(), 0,
|
|
"document thread should have no unread messages initially");
|
|
|
|
// simulate receiving a needaction message on this document thread
|
|
var needactionMessageData = {
|
|
id: 5,
|
|
author_id: [42, "Someone"],
|
|
body: 'important message',
|
|
channel_ids: [],
|
|
res_id: 2,
|
|
model: 'partner',
|
|
needaction: true,
|
|
needaction_partner_ids: [3],
|
|
};
|
|
this.data['mail.message'].records.push(needactionMessageData);
|
|
var notification = [[false, 'mail.channel', 1], needactionMessageData];
|
|
form.call('bus_service', 'trigger', 'notification', [notification]);
|
|
await testUtils.nextMicrotaskTick();
|
|
assert.strictEqual(thread.getUnreadCounter(), 1,
|
|
"document thread should now have one unread message");
|
|
|
|
// do not destroy form too early. wait rendering to avoid race condition in service call.
|
|
await testUtils.nextTick();
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: access document with some notifs', async function (assert) {
|
|
assert.expect(3);
|
|
|
|
// simulate received needaction message on this document thread
|
|
var needactionMessageData = {
|
|
id: 5,
|
|
author_id: [42, "Someone"],
|
|
body: 'important message',
|
|
channel_ids: [],
|
|
res_id: 2,
|
|
model: 'partner',
|
|
needaction: true,
|
|
needaction_partner_ids: [3],
|
|
};
|
|
this.data['mail.message'].records.push(needactionMessageData);
|
|
this.data['partner'].records[0].message_ids = [5];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {
|
|
partner_id: 3,
|
|
},
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'set_message_done') {
|
|
assert.step('set_message_done');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.verifySteps(['set_message_done']);
|
|
|
|
var thread = form.call('mail_service', 'getDocumentThread', 'partner', 2);
|
|
assert.strictEqual(thread.getUnreadCounter(), 0,
|
|
"document thread should have no unread messages (marked as read)");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: post a message and switch in edit mode', async function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'message_post') {
|
|
this.data['mail.message'].records.push({
|
|
attachment_ids: args.kwargs.attachment_ids,
|
|
author_id: ["42", "Me"],
|
|
body: args.kwargs.body,
|
|
date: "2016-12-20 10:35:40",
|
|
id: 42,
|
|
is_note: args.kwargs.subtype === 'mail.mt_note',
|
|
is_discussion: args.kwargs.subtype === 'mail.mt_comment',
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
return Promise.resolve(42);
|
|
}
|
|
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
assert.containsNone(form, '.o_thread_message', "thread should not contain messages");
|
|
|
|
// send a message
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
assert.containsOnce(form, '.o_thread_message', "thread should contain a message");
|
|
assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first message') >= 0,
|
|
"the message's body should be correct");
|
|
|
|
// switch in edit mode
|
|
await testUtils.form.clickEdit(form);
|
|
assert.containsOnce(form, '.o_thread_message', "thread should contain a message");
|
|
assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first message') >= 0,
|
|
"the message's body should be correct");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: discard changes on message post with post_refresh "always"', async function (assert) {
|
|
// After posting a message that always reloads the record, if the record
|
|
// is dirty (= has some unsaved changes), we should warn the user that
|
|
// these changes will be lost if he proceeds.
|
|
assert.expect(2);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"' +
|
|
' options="{\'display_log_button\': True, \'post_refresh\': \'always\'}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === "/mail/get_suggested_recipients") {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
// Make record dirty
|
|
await testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu');
|
|
|
|
// Send a message
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
|
|
var $modal = $('.modal-dialog');
|
|
assert.strictEqual($modal.length, 1, "should have a modal opened");
|
|
assert.strictEqual($modal.find('.modal-body').text(),
|
|
"The record has been modified, your changes will be discarded. Do you want to proceed?",
|
|
"should warn the user that any unsaved changes will be lost");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: discard changes on message post without post_refresh', async function (assert) {
|
|
// After posting a message, if the record is dirty and there are no
|
|
// post_refresh rule, it will not discard the changes on the record.
|
|
assert.expect(2);
|
|
|
|
var hasDiscardChanges = false; // set if `discard_changes` has been triggered up
|
|
var messages = [];
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"' +
|
|
' options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === "/mail/get_suggested_recipients") {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'message_format') {
|
|
var requested_msgs = _.filter(messages, function (msg) {
|
|
return _.contains(args.args[0], msg.id);
|
|
});
|
|
return Promise.resolve(requested_msgs);
|
|
}
|
|
if (args.method === 'message_post') {
|
|
messages.push({
|
|
attachment_ids: [],
|
|
author_id: ["42", "Me"],
|
|
body: args.kwargs.body,
|
|
date: moment().format('YYYY-MM-DD HH:MM:SS'), // now
|
|
displayed_author: "Me",
|
|
id: 42,
|
|
is_note: args.kwargs.subtype === 'mail.mt_note',
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
return Promise.resolve(42);
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
intercepts: {
|
|
discard_changes: function () {
|
|
hasDiscardChanges = true; // should not do that
|
|
},
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
// Make record dirty
|
|
await testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu');
|
|
|
|
// Send a message
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
|
|
var $modal = $('.modal-dialog');
|
|
assert.strictEqual($modal.length, 0, "should have no modal opened");
|
|
assert.notOk(hasDiscardChanges);
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: discard changes on message post with post_refresh "recipients"', async function (assert) {
|
|
// After posting a message with mentions, the record will be reloaded,
|
|
// as the rpc `message_post` may make changes on some fields of the record.
|
|
// If the record is dirty (= has some unsaved changes), we should warn the
|
|
// user that these changes will be lost if he proceeds.
|
|
assert.expect(2);
|
|
|
|
var getSuggestionsDef = testUtils.makeTestPromise();
|
|
|
|
var messages = [];
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"' +
|
|
' options="{\'display_log_button\': True, \'post_refresh\': \'recipients\'}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === "/mail/get_suggested_recipients") {
|
|
return Promise.resolve({2: [[42, "Me"]]});
|
|
}
|
|
if (args.method === 'get_mention_suggestions') {
|
|
getSuggestionsDef.resolve();
|
|
return Promise.resolve([[{email: "me@odoo.com", id: 42, name: "Me"}], []]);
|
|
}
|
|
if (args.method === 'message_format') {
|
|
var requested_msgs = _.filter(messages, function (msg) {
|
|
return _.contains(args.args[0], msg.id);
|
|
});
|
|
return Promise.resolve(requested_msgs);
|
|
}
|
|
if (args.method === 'message_post') {
|
|
messages.push({
|
|
attachment_ids: [],
|
|
author_id: ["42", "Me"],
|
|
body: args.kwargs.body,
|
|
date: moment().format('YYYY-MM-DD HH:MM:SS'), // now
|
|
displayed_author: "Me",
|
|
id: 42,
|
|
is_note: args.kwargs.subtype === 'mail.mt_note',
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
return Promise.resolve(42);
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
// Make record dirty
|
|
await testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu');
|
|
|
|
// create a new message
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
|
|
// Add a user as mention
|
|
await testUtils.fields.editInput(form.$('.oe_chatter .o_composer_text_field:first()'), "@");
|
|
|
|
var $input = form.$('.oe_chatter .o_composer_text_field:first()');
|
|
$input.val('@');
|
|
// the cursor position must be set for the mention manager to detect that we are mentionning
|
|
$input[0].selectionStart = 1;
|
|
$input[0].selectionEnd = 1;
|
|
$input.trigger('keyup');
|
|
await getSuggestionsDef;
|
|
await testUtils.nextTick();
|
|
// click on mention
|
|
$input.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER}));
|
|
await testUtils.nextTick();
|
|
|
|
// untick recipient as follower (prompts a res.partner form otherwise)
|
|
form.$('input[type="checkbox"]').prop('checked', false);
|
|
await testUtils.nextTick();
|
|
// send message
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
|
|
var $modal = $('.modal-dialog');
|
|
assert.strictEqual($modal.length, 1, "should have a modal opened");
|
|
assert.strictEqual($modal.find('.modal-body').text(),
|
|
"The record has been modified, your changes will be discarded. Do you want to proceed?",
|
|
"should warn the user that any unsaved changes will be lost");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: discard changes on opening full-composer and open missing partner info popup', async function (assert) {
|
|
// When we open the full-composer, any following operations by the user
|
|
// will reload the record (even closing the full-composer). Therefore,
|
|
// we should warn the user when we open the full-composer if the record
|
|
// is dirty (= has some unsaved changes).
|
|
assert.expect(3);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"' +
|
|
' options="{\'display_log_button\': True,' +
|
|
' \'post_refresh\': \'always\'}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
archs: {
|
|
'res.partner,false,form':
|
|
'<form string="partners">' +
|
|
'<field name="name"/>' +
|
|
'</form>',
|
|
},
|
|
res_id: 2,
|
|
session: {},
|
|
mockRPC: function (route, args) {
|
|
if (route === "/mail/get_suggested_recipients") {
|
|
return Promise.resolve({2: [[
|
|
false,
|
|
'pikapika@pikachu.com',
|
|
''
|
|
]]});
|
|
}
|
|
if (route === "/mail/get_partner_info") {
|
|
return Promise.resolve([{full_name: "pikapika@pikachu.com", partner_id: false}]);
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
// Make record dirty
|
|
await testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu');
|
|
|
|
// Open full-composer
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
await testUtils.dom.click(form.$('.o_composer_button_full_composer'));
|
|
|
|
var $modal = $('.modal-dialog');
|
|
assert.strictEqual($modal.length, 1, "should have a modal opened");
|
|
assert.strictEqual($modal.find('.modal-body').text(),
|
|
"The record has been modified, your changes will be discarded. Do you want to proceed?",
|
|
"should warn the user that any unsaved changes will be lost");
|
|
await testUtils.dom.click($modal.find('.modal-footer .btn.btn-primary'));
|
|
assert.strictEqual($modal.length, 1, "should have a modal opened");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter in x2many form view', async function (assert) {
|
|
// the purpose of this test is to ensure that it doesn't crash when a x2many
|
|
// record is opened in form view (thus in a dialog), and when there is a
|
|
// chatter in the arch (typically, this may occur when the view used for the
|
|
// x2many is a default one, which is also used in another context, as the
|
|
// chatter is hidden in the dialog anyway)
|
|
assert.expect(2);
|
|
|
|
this.data.partner.fields.o2m = {
|
|
string: "one2many field", type: "one2many", relation: 'partner',
|
|
};
|
|
this.data.partner.records[0].o2m = [2];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form><field name="o2m"/></form>',
|
|
archs: {
|
|
'partner,false,form': '<form>' +
|
|
'<field name="foo"/>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
'partner,false,list': '<tree><field name="display_name"/></tree>',
|
|
},
|
|
res_id: 2,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
await testUtils.dom.click(form.$('.o_data_row:first'));
|
|
|
|
assert.strictEqual($('.modal .o_form_view').length, 1,
|
|
"should have open a form view in a modal");
|
|
assert.strictEqual($('.modal .o_chatter:visible').length, 0,
|
|
"chatter should be hidden (as in a dialog)");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: Attachment viewer', async function (assert) {
|
|
assert.expect(6);
|
|
this.data.partner.records[0].message_ids = [1];
|
|
this.data['mail.message'].records = [{
|
|
attachment_ids: [{
|
|
filename: 'image1.jpg',
|
|
id:1,
|
|
checksum: 999,
|
|
mimetype: 'image/jpeg',
|
|
name: 'Test Image 1',
|
|
url: '/web/content/1?download=true'
|
|
},{
|
|
filename: 'image2.jpg',
|
|
id:2,
|
|
checksum: 999,
|
|
mimetype: 'image/jpeg',
|
|
name: 'Test Image 2',
|
|
url: '/web/content/2?download=true'
|
|
},{
|
|
filename: 'image3.jpg',
|
|
id:3,
|
|
checksum: 999,
|
|
mimetype: 'image/jpeg',
|
|
name: 'Test Image 3',
|
|
url: '/web/content/3?download=true'
|
|
},{
|
|
filename: 'pdf1.pdf',
|
|
id:4,
|
|
mimetype: 'application/pdf',
|
|
name: 'Test PDF 1',
|
|
url: '/web/content/4?download=true'
|
|
}],
|
|
author_id: ["1", "John Doe"],
|
|
body: "Attachement viewer test",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 1,
|
|
is_note: false,
|
|
is_discussion: true,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (_.str.contains(route, '/mail/attachment/preview/') ||
|
|
_.str.contains(route, '/web/static/lib/pdfjs/web/viewer.html')){
|
|
var canvas = document.createElement('canvas');
|
|
return Promise.resolve(canvas.toDataURL());
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
assert.containsN(form, '.o_thread_message .o_attachment', 4,
|
|
"there should be three attachment on message");
|
|
assert.hasAttrValue(form.$('.o_thread_message .o_attachment a').first(), 'href', '/web/content/1?download=true',
|
|
"image caption should have correct download link");
|
|
// click on first image attachement
|
|
await testUtils.dom.click(form.$('.o_thread_message .o_attachment .o_image_box .o_image_overlay').first());
|
|
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/1?unique=1&signature=999&model=ir.attachment"]').length, 1,
|
|
"Modal popup should open with first image src");
|
|
// click on next button
|
|
await testUtils.dom.click($('.modal .arrow.arrow-right.move_next span'));
|
|
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/2?unique=1&signature=999&model=ir.attachment"]').length, 1,
|
|
"Modal popup should have now second image src");
|
|
assert.strictEqual($('.o_modal_fullscreen .o_viewer_toolbar .o_download_btn').length, 1,
|
|
"Modal popup should have download button");
|
|
// close attachment popup
|
|
await testUtils.dom.click($('.o_modal_fullscreen .o_viewer-header .o_close_btn'));
|
|
// click on pdf attachement
|
|
await testUtils.dom.click(form.$('span:contains(Test PDF 1)'));
|
|
assert.strictEqual($('.o_modal_fullscreen iframe[data-src*="/web/content/4"]').length, 1,
|
|
"Modal popup should open with the pdf preview");
|
|
// close attachment popup
|
|
await testUtils.dom.click($('.o_modal_fullscreen .o_viewer-header .o_close_btn'));
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: keep context when sending a message', async function(assert) {
|
|
assert.expect(1);
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {
|
|
user_context: {lang: 'en_US'},
|
|
},
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'message_post') {
|
|
assert.deepEqual(args.kwargs.context, {
|
|
default_model: "partner",
|
|
default_res_id: 2,
|
|
lang: "en_US",
|
|
mail_post_autofollow: true,
|
|
},
|
|
"the context is incorrect");
|
|
return Promise.resolve(57923);
|
|
}
|
|
if (args.method === 'message_format') {
|
|
return Promise.resolve([{
|
|
author_id: [42, "Me"],
|
|
model: 'partner',
|
|
}]);
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
});
|
|
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
await testUtils.fields.editInput(form.$('.oe_chatter .o_composer_text_field:first()'), 'Pouet');
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget: read RPCs', async function (assert) {
|
|
// Records of model 'mail.activity' may be updated in business flows (e.g.
|
|
// the date of a 'Meeting' activity is updated when the associated meeting
|
|
// is dragged&dropped in the Calendar view). Because of that, the activities
|
|
// must be reloaded when the form is reloaded (the widget can't keep an
|
|
// internal cache).
|
|
assert.expect(6);
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 2,
|
|
}];
|
|
|
|
var nbReads = 0;
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'activity_format' && args.model === 'mail.activity') {
|
|
nbReads++;
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(nbReads, 1, "should have read the activities");
|
|
assert.containsOnce(form, '.o_mail_activity .o_thread_message',
|
|
"should display an activity");
|
|
assert.strictEqual(form.$('.o_mail_activity .o_thread_message .o_activity_date').text(),
|
|
'Today', "the activity should be today");
|
|
|
|
await testUtils.form.clickEdit(form);
|
|
await testUtils.form.clickSave(form);
|
|
|
|
assert.strictEqual(nbReads, 1, "should not have re-read the activities");
|
|
|
|
// simulate a date change, and a reload of the form view
|
|
var tomorrow = moment().add(1, 'day').format("YYYY-MM-DD");
|
|
this.data['mail.activity'].records[0].date_deadline = tomorrow;
|
|
await form.reload();
|
|
|
|
assert.strictEqual(nbReads, 2, "should have re-read the activities");
|
|
assert.strictEqual(form.$('.o_mail_activity .o_thread_message .o_activity_date').text(),
|
|
'Tomorrow', "the activity should be tomorrow");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget on a new record', async function (assert) {
|
|
assert.expect(0);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read' && args.model === 'mail.activity') {
|
|
throw new Error("should not do a read on mail.activity");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget with another x2many field in view', async function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.fields.m2m = {string: "M2M", type: 'many2many', relation: 'partner'};
|
|
|
|
this.data.partner.records[0].m2m = [2];
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="m2m" widget="many2many_tags"/>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.containsOnce(form, '.o_mail_activity .o_thread_message',
|
|
"should display an activity");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget: schedule next activity', async function (assert) {
|
|
assert.expect(4);
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<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 === '/web/dataset/call_kw/mail.activity/action_feedback_schedule_next') {
|
|
assert.ok(_.isEqual(args.args[0], [1]), "should call 'action_feedback_schedule_next' for id 1");
|
|
assert.strictEqual(args.kwargs.feedback, 'everything is ok',
|
|
"the feedback should be sent correctly");
|
|
return Promise.resolve('test_result');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
intercepts: {
|
|
do_action: function (event) {
|
|
assert.strictEqual(event.data.action,'test_result' , "should do a do_action with correct parameters");
|
|
event.data.options.on_close();
|
|
},
|
|
},
|
|
});
|
|
//Schedule next activity
|
|
await testUtils.dom.click(form.$('.o_mail_activity .o_mark_as_done[data-activity-id=1]'));
|
|
assert.containsOnce(form, '.o_mail_activity_feedback.popover',
|
|
"a feedback popover should be visible");
|
|
$('.o_mail_activity_feedback.popover textarea').val('everything is ok'); // write a feedback
|
|
await testUtils.dom.click(form.$('.o_activity_popover_done_next'));
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget: do not close activity popover on click', async function (assert) {
|
|
assert.expect(3);
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_user_id: 2,
|
|
activity_type_id: 2,
|
|
}];
|
|
|
|
const form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: `<form string="Partners">
|
|
<sheet>
|
|
<field name="foo"/>
|
|
</sheet>
|
|
<div class="oe_chatter">
|
|
<field name="message_ids" widget="mail_thread"/>
|
|
<field name="activity_ids" widget="mail_activity"/>
|
|
</div>
|
|
</form>`,
|
|
res_id: 2,
|
|
mockRPC(route, args) {
|
|
if (route === '/web/dataset/call_kw/mail.activity/action_feedback_schedule_next') {
|
|
return Promise.resolve();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
intercepts: {
|
|
do_action(ev) {
|
|
ev.data.options.on_close();
|
|
},
|
|
},
|
|
});
|
|
|
|
//Schedule next activity
|
|
await testUtils.dom.click(form.$('.o_mail_activity .o_mark_as_done[data-activity-id=1]'));
|
|
|
|
for (let i = 0; i < 2; i++) {
|
|
// click twice in feedback area
|
|
await testUtils.dom.click(form.$('.o_mail_activity_feedback.popover textarea'));
|
|
const $popover = form.$('.o_mail_activity_feedback.popover');
|
|
const $PopoverInDom = form.$(`#${$popover.attr('id')}`);
|
|
assert.isVisible(
|
|
$PopoverInDom,
|
|
"the feedback popover should still be visible on click");
|
|
}
|
|
await concurrency.delay(250); // wait for popover transition
|
|
const $popover = form.$('.o_mail_activity_feedback.popover');
|
|
if (!$popover) {
|
|
throw new Error("popover should be in DOM");
|
|
}
|
|
const $PopoverInDom = form.$(`#${$popover.attr('id')}`);
|
|
assert.isVisible(
|
|
$PopoverInDom,
|
|
"the feedback popover should still be visible on click");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
|
|
QUnit.test('form activity widget: edit next activity', async function (assert) {
|
|
assert.expect(3);
|
|
var self = this;
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
intercepts: {
|
|
do_action: function (event) {
|
|
assert.deepEqual(event.data.action, {
|
|
context: {
|
|
default_res_id: 2,
|
|
default_res_model: "partner"
|
|
},
|
|
name: "Schedule Activity",
|
|
res_id: 1,
|
|
res_model: "mail.activity",
|
|
target: "new",
|
|
type: "ir.actions.act_window",
|
|
view_mode: "form",
|
|
views: [
|
|
[
|
|
false,
|
|
"form"
|
|
]
|
|
]
|
|
},
|
|
"should do a do_action with correct parameters");
|
|
self.data['mail.activity'].records[0].activity_type_id = 1;
|
|
event.data.options.on_close();
|
|
},
|
|
},
|
|
});
|
|
assert.strictEqual(form.$('.o_mail_activity .o_mail_info strong:eq(1)').text(), " Type 2",
|
|
"Initial type should be Type 2");
|
|
await testUtils.dom.click(form.$('.o_mail_activity .o_edit_activity[data-activity-id=1]'));
|
|
assert.strictEqual(form.$('.o_mail_activity .o_mail_info strong:eq(1)').text(), " Type 1",
|
|
"After edit type should be Type 1");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget: clic mail template', async function (assert) {
|
|
assert.expect(4);
|
|
this.data.partner.records[0].activity_ids = [1];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
activity_type_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread"/>' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'activity_format') {
|
|
return this._super.apply(this, arguments).then(function (res) {
|
|
res[0].mail_template_ids = [{ id: 100, name: 'Temp1' }];
|
|
return res;
|
|
});
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
intercepts: {
|
|
do_action: function (ev) {
|
|
assert.deepEqual(ev.data.action, {
|
|
name: _t('Compose Email'),
|
|
type: 'ir.actions.act_window',
|
|
res_model: 'mail.compose.message',
|
|
views: [[false, 'form']],
|
|
target: 'new',
|
|
context: {
|
|
default_res_id: 2,
|
|
default_model: 'partner',
|
|
default_use_template: true,
|
|
default_template_id: 100,
|
|
force_email: true,
|
|
},
|
|
},
|
|
"should do a do_action with correct parameters");
|
|
ev.data.options.on_close();
|
|
},
|
|
},
|
|
});
|
|
assert.containsOnce(form, '.o_mail_activity .o_thread_message',
|
|
"we should have one activity");
|
|
assert.containsOnce(form, '.o_activity_template_preview',
|
|
"Activity should contains one mail template");
|
|
await testUtils.dom.click(form.$('.o_activity_template_preview[data-template-id=100]'));
|
|
assert.containsOnce(form, '.o_mail_activity .o_thread_message',
|
|
"activity should still be there");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget: schedule activity does not discard changes', async function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="activity_ids" widget="mail_activity"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'write') {
|
|
assert.deepEqual(args.args[1], {foo: 'new value'},
|
|
"should correctly save the change");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
intercepts: {
|
|
do_action: function (event) {
|
|
event.data.options.on_close();
|
|
},
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
// update value of foo field
|
|
await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'new value');
|
|
|
|
// schedule an activity (this triggers a do_action)
|
|
await testUtils.dom.click(form.$('.o_chatter_button_schedule_activity'));
|
|
|
|
// save the record
|
|
await testUtils.form.clickSave(form);
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('form activity widget: mark as done and remove', async function (assert) {
|
|
assert.expect(15);
|
|
|
|
var self = this;
|
|
|
|
var nbReads = 0;
|
|
this.data.partner.records[0].activity_ids = [1, 2];
|
|
this.data.partner.records[0].activity_state = 'today';
|
|
this.data['mail.activity'].records = [{
|
|
id: 1,
|
|
display_name: "An activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 1,
|
|
}, {
|
|
id: 2,
|
|
display_name: "A second activity",
|
|
date_deadline: moment().format("YYYY-MM-DD"), // now
|
|
can_write: true,
|
|
state: "today",
|
|
user_id: 2,
|
|
create_uid: 2,
|
|
activity_type_id: 1,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<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 === '/web/dataset/call_kw/mail.activity/unlink') {
|
|
assert.ok(_.isEqual(args.args[0], [1]), "should call 'unlink' for id 1");
|
|
} else if (route === '/web/dataset/call_kw/mail.activity/action_feedback') {
|
|
assert.ok(_.isEqual(args.args[0], [2]), "should call 'action_feedback' for id 2");
|
|
assert.strictEqual(args.kwargs.feedback, 'everything is ok',
|
|
"the feedback should be sent correctly");
|
|
// should generate a message and unlink the activity
|
|
self.data.partner.records[0].message_ids = [1];
|
|
this.data['mail.message'].records.push({
|
|
attachment_ids: [],
|
|
author_id: ["1", "John Doe"],
|
|
body: "The activity has been done",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 1,
|
|
is_note: true,
|
|
is_discussion: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
route = '/web/dataset/call_kw/mail.activity/unlink';
|
|
args.method = 'unlink';
|
|
} else if (route === '/web/dataset/call_kw/partner/read') {
|
|
nbReads++;
|
|
if (nbReads === 1) { // first read
|
|
assert.strictEqual(args.args[1].length, 5, 'should read all fiels the first time');
|
|
} else if (nbReads === 2) { // second read: after the unlink
|
|
assert.ok(_.isEqual(args.args[1], ['activity_ids', 'display_name']),
|
|
'should only read the activities (+ display_name) after an unlink');
|
|
} else { // third read: after marking an activity done
|
|
assert.ok(_.isEqual(args.args[1], ['activity_ids', 'message_ids', 'display_name']),
|
|
'should read the activities and messages (+ display_name) after marking an activity done');
|
|
}
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.containsN(form, '.o_mail_activity .o_thread_message', 2,
|
|
"there should be two activities");
|
|
|
|
// remove activity 1
|
|
await testUtils.dom.click(form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]'));
|
|
assert.containsOnce(form, '.o_mail_activity .o_thread_message',
|
|
"there should be one remaining activity");
|
|
assert.ok(!form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]').length,
|
|
"activity 1 should have been removed");
|
|
|
|
// mark activity done
|
|
assert.ok(!form.$('.o_mail_thread .o_thread_message').length,
|
|
"there should be no chatter message");
|
|
await testUtils.dom.click(form.$('.o_mail_activity .o_mark_as_done[data-activity-id=2]'));
|
|
assert.containsOnce(form, '.o_mail_activity_feedback.popover',
|
|
"a feedback popover should be visible");
|
|
$('.o_mail_activity_feedback.popover textarea').val('everything is ok'); // write a feedback
|
|
await testUtils.dom.click(form.$('.o_activity_popover_done'));
|
|
assert.containsNone(form, '.o_mail_activity_feedback.popover')
|
|
assert.ok(!form.$('.o_mail_activity .o_thread_message').length,
|
|
"there should be no more activity");
|
|
assert.containsOnce(form, '.o_mail_thread .o_thread_message',
|
|
"a chatter message should have been generated");
|
|
assert.strictEqual(form.$('.o_thread_message:contains(The activity has been done)').length, 1,
|
|
"the message's body should be correct");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('followers widget: follow/unfollow, edit subtypes', async function (assert) {
|
|
assert.expect(14);
|
|
|
|
var resID = 2;
|
|
var partnerID = 2;
|
|
var followers = [];
|
|
var nbReads = 0;
|
|
var subtypes = [
|
|
{id: 1, name: "First subtype", followed: true},
|
|
{id: 2, name: "Second subtype", followed: true},
|
|
{id: 3, name: "Third subtype", followed: false},
|
|
];
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_follower_ids" widget="mail_followers"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: resID,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/message_subscribe') {
|
|
assert.strictEqual(args.args[0][0], resID, 'should call route for correct record');
|
|
assert.ok(_.isEqual(args.kwargs.partner_ids, [partnerID]),
|
|
'should call route for correct partner');
|
|
if (args.kwargs.subtype_ids) {
|
|
// edit subtypes
|
|
assert.ok(_.isEqual(args.kwargs.subtype_ids, [1]),
|
|
'should call route with the correct subtypes');
|
|
_.each(subtypes, function (subtype) {
|
|
subtype.followed = _.contains(args.kwargs.subtype_ids, subtype.id);
|
|
});
|
|
} else {
|
|
// follow
|
|
this.data.partner.records[0].message_follower_ids = [1];
|
|
followers.push({
|
|
id: 1,
|
|
is_uid: true,
|
|
name: "Admin",
|
|
email: "admin@example.com",
|
|
res_id: resID,
|
|
res_model: 'partner',
|
|
});
|
|
}
|
|
return Promise.resolve(true);
|
|
}
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve({
|
|
followers: followers,
|
|
subtypes: subtypes,
|
|
// caution, subtype will only be returned if current user is in args follower list
|
|
});
|
|
}
|
|
if (route === '/web/dataset/call_kw/partner/message_unsubscribe') {
|
|
assert.strictEqual(args.args[0][0], resID, 'should call route for correct record');
|
|
assert.ok(_.isEqual(args.args[1], [partnerID]), 'should call route for correct partner');
|
|
this.data.partner.records[0].message_follower_ids = [];
|
|
followers = [];
|
|
return Promise.resolve(true);
|
|
}
|
|
if (route === '/web/dataset/call_kw/partner/read') {
|
|
nbReads++;
|
|
if (nbReads === 1) { // first read: should read all fields
|
|
assert.strictEqual(args.args[1].length, 3,
|
|
'should read "foo", "message_follower_ids" and "display_name"');
|
|
} else { // three next reads: only read 'message_follower_ids' field
|
|
assert.deepEqual(args.args[1], ['message_follower_ids', 'display_name'],
|
|
'should only read "message_follower_ids" and "display_name"');
|
|
}
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
session: {partner_id: partnerID},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "0", 'should have no followers');
|
|
assert.ok(form.$('.o_followers_follow_button.o_followers_notfollow').length,
|
|
'should display the "Follow" button');
|
|
|
|
// click to follow the document
|
|
await testUtils.dom.click(form.$('.o_followers_follow_button'));
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "1", 'should have one follower');
|
|
assert.ok(form.$('.o_followers_follow_button.o_followers_following').length,
|
|
'should display the "Following/Unfollow" button');
|
|
assert.containsOnce(form, '.o_followers_list .o_partner',
|
|
"there should be one follower in the follower dropdown");
|
|
|
|
// click to unfollow
|
|
await testUtils.dom.click(form.$('.o_followers_follow_button'));
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "0", 'should have no followers');
|
|
assert.ok(form.$('.o_followers_follow_button.o_followers_notfollow').length,
|
|
'should display the "Follow" button');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('followers widget: follow/unfollow confirmation dialog', async function (assert) {
|
|
assert.expect(5);
|
|
|
|
this.data.partner.records[0].message_follower_ids = [1, 2];
|
|
var resID = 2;
|
|
var partnerID = 2;
|
|
var followers = [{
|
|
id: 1,
|
|
is_uid: true,
|
|
name: "Admin",
|
|
email: "admin@example.com",
|
|
res_id: resID,
|
|
res_model: 'res.partner',
|
|
}, {
|
|
id: 2,
|
|
is_uid: true,
|
|
name: "Demo",
|
|
email: "demo@example.com",
|
|
res_id: 3,
|
|
res_model: 'res.partner',
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_follower_ids" widget="mail_followers"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: resID,
|
|
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/message_unsubscribe') {
|
|
this.data.partner.records[0].message_follower_ids.shift();
|
|
followers.shift();
|
|
return Promise.resolve(true);
|
|
}
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve({
|
|
followers: followers,
|
|
});
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
session: {partner_id: partnerID},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "2", 'should have 2 followers');
|
|
// click to unfollow current user
|
|
await testUtils.dom.click(form.$('.o_followers_follow_button'));
|
|
assert.containsNone($, '.modal', 'a confirm modal should not be opened');
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "1", 'should have 1 follower');
|
|
|
|
await testUtils.dom.click(form.$('.o_followers_title_box [data-toggle="dropdown"]'));
|
|
// remove demo user from followers
|
|
await testUtils.dom.click(form.$('.o_remove_follower'));
|
|
assert.containsOnce($, '.modal', 'a confirm modal should be opened');
|
|
await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "0", 'should have no followers');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('followers widget: do not display follower duplications', async function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.records[0].message_follower_ids = [1];
|
|
var resID = 2;
|
|
var followers = [{
|
|
id: 1,
|
|
name: "Admin",
|
|
email: "admin@example.com",
|
|
res_id: resID,
|
|
res_model: 'partner',
|
|
}];
|
|
var def;
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form>' +
|
|
'<sheet></sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_follower_ids" widget="mail_followers"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve(def).then(function () {
|
|
return {
|
|
followers: _.filter(followers, function (follower) {
|
|
return _.contains(args.follower_ids, follower.id);
|
|
}),
|
|
subtypes: [],
|
|
};
|
|
});
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
res_id: resID,
|
|
session: {partner_id: 1},
|
|
});
|
|
|
|
|
|
followers.push({
|
|
id: 2,
|
|
is_uid: false,
|
|
name: "A follower",
|
|
email: "follower@example.com",
|
|
res_id: resID,
|
|
res_model: 'partner',
|
|
});
|
|
this.data.partner.records[0].message_follower_ids.push(2);
|
|
|
|
// simulate concurrent calls to read_followers and check that those followers
|
|
// are not added twice in the dropdown
|
|
def = testUtils.makeTestPromise();
|
|
form.reload();
|
|
form.reload();
|
|
await def.resolve();
|
|
await testUtils.nextTick();
|
|
assert.strictEqual(form.$('.o_followers_count').text(), '2',
|
|
"should have 2 followers");
|
|
assert.containsN(form, '.o_followers_list .o_partner', 2,
|
|
"there should be 2 followers in the follower dropdown");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('followers widget: display inactive followers with a different style', async function (assert) {
|
|
assert.expect(6);
|
|
|
|
this.data.partner.records[0].message_follower_ids = [1,2,3];
|
|
|
|
var followers = [{
|
|
id: 1,
|
|
name: "Admin",
|
|
email: "admin@example.com",
|
|
res_id: 101,
|
|
res_model: 'partner',
|
|
active: true,
|
|
},{
|
|
id: 2,
|
|
name: "Active_partner",
|
|
email: "active_partner@example.com",
|
|
res_id: 102,
|
|
res_model: 'partner',
|
|
active: true,
|
|
},{
|
|
id: 3,
|
|
name: "Inactive_partner",
|
|
email: "inactive_partner@example.com",
|
|
res_id: 103,
|
|
res_model: 'partner',
|
|
active: false,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_follower_ids" widget="mail_followers"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve({
|
|
followers: _.filter(followers, function (follower) {
|
|
return _.contains(args.follower_ids, follower.id);
|
|
}),
|
|
});
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.doesNotHaveClass(form.$(".o_partner:has(a[data-oe-id='101'])"), 'o_inactive', 'Partner should be active');
|
|
assert.hasAttrValue(form.$(".o_partner:has(a[data-oe-id='101']) > a"),'title','Admin');
|
|
assert.doesNotHaveClass(form.$(".o_partner:has(a[data-oe-id='102'])"), 'o_inactive', 'Partner should be active');
|
|
assert.hasAttrValue(form.$(".o_partner:has(a[data-oe-id='102']) > a"),'title','Active_partner');
|
|
assert.hasClass(form.$(".o_partner:has(a[data-oe-id='103'])"), 'o_inactive', 'Partner should be inactive');
|
|
assert.hasAttrValue(form.$(".o_partner:has(a[data-oe-id='103']) > a"),'title','Inactive_partner \n(inactive)');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('does not render and crash when destroyed before chat system is ready', async function (assert) {
|
|
assert.expect(0);
|
|
|
|
var def = testUtils.makeTestPromise();
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
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 (args.method === 'message_format') {
|
|
return Promise.resolve([{
|
|
attachment_ids: [],
|
|
body: "",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 34,
|
|
res_id: 3,
|
|
author_id: ["3", "Fu Ck Mil Grom"],
|
|
}]);
|
|
}
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve({
|
|
followers: [],
|
|
subtypes: [],
|
|
});
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
intercepts: {
|
|
get_session: function (event) {
|
|
event.stopPropagation();
|
|
event.data.callback({uid: 1, origin: 'http://web'});
|
|
},
|
|
},
|
|
});
|
|
|
|
form.destroy();
|
|
// here, the chat service 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 the chat bus)
|
|
await def.resolve();
|
|
});
|
|
|
|
QUnit.test('chatter: do not duplicate messages on (un)star message', async function (assert) {
|
|
assert.expect(4);
|
|
|
|
this.data.partner.records[0].message_ids = [1];
|
|
this.data['mail.message'].records = [{
|
|
author_id: ["1", "John Doe"],
|
|
body: "A message",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 1,
|
|
is_note: false,
|
|
is_discussion: true,
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'toggle_message_starred') {
|
|
var messageData = _.findWhere(
|
|
this.data['mail.message'].records,
|
|
{ id: args.args[0][0] }
|
|
);
|
|
messageData.is_starred = !messageData.is_starred;
|
|
// simulate notification received by mail_service from longpoll
|
|
var data = {
|
|
info: false,
|
|
message_ids: [messageData.id],
|
|
starred: messageData.is_starred,
|
|
type: 'toggle_star',
|
|
};
|
|
var notification = [[false, 'res.partner'], data];
|
|
form.call('bus_service', 'trigger', 'notification', [notification]);
|
|
return Promise.resolve();
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
session: {},
|
|
});
|
|
|
|
assert.containsOnce(form, '.o_thread_message',
|
|
"there should be a single message in the chatter");
|
|
assert.ok(form.$('.o_thread_message .o_thread_message_star.fa-star-o').length,
|
|
"message should not be starred");
|
|
|
|
// star message
|
|
await testUtils.dom.click(form.$('.o_thread_message .o_thread_message_star'));
|
|
assert.containsOnce(form, '.o_thread_message',
|
|
"there should still be a single message in the chatter after starring the message");
|
|
|
|
// unstar message
|
|
await testUtils.dom.click(form.$('.o_thread_message .o_thread_message_star'));
|
|
assert.containsOnce(form, '.o_thread_message',
|
|
"there should still be a single message in the chatter after unstarring the message");
|
|
|
|
//cleanup
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: new messages on document without any "display_name"', async function (assert) {
|
|
assert.expect(5);
|
|
|
|
this.data.partner.records[0].message_ids = [1];
|
|
this.data.partner.records[0].display_name = false;
|
|
this.data['mail.message'].records = [{
|
|
author_id: [1, "John Doe"],
|
|
body: "A message",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 1,
|
|
is_note: false,
|
|
is_discussion: true,
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
}];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'<div class="oe_chatter">' +
|
|
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {},
|
|
});
|
|
|
|
assert.containsOnce(form, '.o_thread_message',
|
|
"should have a single message in the chatter");
|
|
assert.containsOnce(form, '.o_thread_message[data-message-id="1"]',
|
|
"single message should have ID 1");
|
|
|
|
// Simulate a new message in the chatter
|
|
this.data['mail.message'].records.push({
|
|
author_id: [2, "Mister Smith"],
|
|
body: "Second message",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 2,
|
|
is_note: false,
|
|
is_discussion: true,
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
this.data.partner.records[0].message_ids.push(2);
|
|
|
|
await form.reload();
|
|
|
|
assert.containsN(form, '.o_thread_message', 2,
|
|
"should have a two messages in the chatter after reload");
|
|
assert.containsOnce(form, '.o_thread_message[data-message-id="1"]',
|
|
"one of the message should have ID 1");
|
|
assert.containsOnce(form, '.o_thread_message[data-message-id="2"]',
|
|
"the other message should have ID 2");
|
|
|
|
//cleanup
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: suggested partner auto-follow on message post', async function (assert) {
|
|
// need post_refresh 'recipient' to auto-follow suggested recipients
|
|
// whose checkbox is checked.
|
|
assert.expect(20);
|
|
|
|
var self = this;
|
|
this.data.partner.records[0].message_follower_ids = [1];
|
|
this.data.partner.records[0].message_ids = [1];
|
|
this.data['mail.message'].records = [{
|
|
author_id: ["1", "John Doe"],
|
|
body: "A message",
|
|
date: "2016-12-20 09:35:40",
|
|
id: 1,
|
|
is_note: false,
|
|
is_discussion: true,
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
}];
|
|
|
|
var followers = [];
|
|
followers.push({
|
|
id: 1,
|
|
is_uid: true,
|
|
name: "Admin",
|
|
email: "admin@example.com",
|
|
res_id: 5,
|
|
res_model: 'partner',
|
|
});
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
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" options="{\'post_refresh\': \'recipients\'}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: [
|
|
[
|
|
8,
|
|
'DemoUser <demo-user@example.com>',
|
|
'Customer Email',
|
|
],
|
|
]
|
|
});
|
|
}
|
|
if (args.method === 'message_post') {
|
|
assert.ok(args.kwargs.context.mail_post_autofollow,
|
|
"should autofollow checked suggested partners when posting message");
|
|
assert.deepEqual(args.kwargs.partner_ids, [8],
|
|
"should have provided Demo User to auto-follow chatter on message_post");
|
|
|
|
// add demo user in followers
|
|
self.data.partner.records[0].message_follower_ids.push(2);
|
|
followers.push({
|
|
id: 2,
|
|
is_uid: true,
|
|
name: "Demo User",
|
|
email: "demo-user@example.com",
|
|
res_id: 8,
|
|
res_model: 'partner',
|
|
});
|
|
|
|
// post a legit message so that it does not crashes
|
|
var lastMessageData = _.max(this.data['mail.message'].records, function (messageData) {
|
|
return messageData.id;
|
|
});
|
|
var messageID = lastMessageData.id + 1;
|
|
this.data['mail.message'].records.push({
|
|
author_id: ["42", "Me"],
|
|
body: args.kwargs.body,
|
|
date: "2016-12-20 10:35:40",
|
|
id: messageID,
|
|
is_note: args.kwargs.subtype === 'mail.mt_note',
|
|
is_discussion: args.kwargs.subtype === 'mail.mt_comment',
|
|
is_notification: false,
|
|
is_starred: false,
|
|
model: 'partner',
|
|
res_id: 2,
|
|
});
|
|
return Promise.resolve(messageID);
|
|
}
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve({
|
|
followers: followers,
|
|
});
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
session: {},
|
|
});
|
|
|
|
assert.containsOnce(form, '.o_thread_message', "thread should contain one message");
|
|
assert.ok(form.$('.o_thread_message:first().o_mail_discussion').length,
|
|
"the message should be a discussion");
|
|
assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('A message') >= 0,
|
|
"the message's body should be correct");
|
|
assert.ok(form.$('.o_thread_message:first() .o_mail_info').text().indexOf('John Doe') >= 0,
|
|
"the message's author should be correct");
|
|
assert.containsOnce(form, '.o_followers',
|
|
"should display follower widget");
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "1",
|
|
"should have a single follower (widget counter)");
|
|
assert.containsOnce(form, '.o_followers_list > div.o_partner',
|
|
"should have a single follower (listed partners)");
|
|
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a').text().trim(), "Admin",
|
|
"should have 'Admin' as follower");
|
|
|
|
// open composer
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
assert.isVisible($('.oe_chatter .o_thread_composer'), "chatter should be opened");
|
|
assert.strictEqual($('.o_composer_suggested_partners').length, 1,
|
|
"should display suggested partners");
|
|
assert.strictEqual($('.o_composer_suggested_partners > div').length, 1,
|
|
"should display 1 suggested partner");
|
|
assert.ok($('.o_composer_suggested_partners input').is(':checked'),
|
|
"should have checkbox that is checked by default");
|
|
assert.strictEqual($('.o_composer_suggested_partners input').data('fullname'),
|
|
"DemoUser <demo-user@example.com>",
|
|
"should have partner suggestion with correct fullname (data)");
|
|
assert.strictEqual($('.o_composer_suggested_partners label').text().replace(/\s+/g, ''),
|
|
"DemoUser(demo-user@example.com)",
|
|
"should have partner suggestion with correct fullname (rendering)");
|
|
|
|
// send message
|
|
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
|
|
await testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send'));
|
|
|
|
assert.strictEqual(form.$('.o_followers_count').text(), "2",
|
|
"should have a two followers (widget counter)");
|
|
assert.containsN(form, '.o_followers_list > div.o_partner', 2,
|
|
"should have two followers (listed partners)");
|
|
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="5"]').text().trim(),
|
|
"Admin",
|
|
"should have 'Admin' as follower");
|
|
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="8"]').text().trim(),
|
|
"Demo User",
|
|
"should have 'Demo User' as follower");
|
|
|
|
//cleanup
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('chatter: mention prefetched partners (followers & employees)', async function (assert) {
|
|
// Note: employees are in prefeteched partner for mentions in chatter when
|
|
// the module hr is installed.
|
|
assert.expect(10);
|
|
|
|
var followerSuggestions = [{
|
|
id: 1,
|
|
name: 'FollowerUser1',
|
|
email: 'follower-user1@example.com',
|
|
}, {
|
|
id: 2,
|
|
name: 'FollowerUser2',
|
|
email: 'follower-user2@example.com',
|
|
}];
|
|
|
|
var nonFollowerSuggestions = [{
|
|
id: 3,
|
|
name: 'NonFollowerUser1',
|
|
email: 'non-follower-user1@example.com',
|
|
}, {
|
|
id: 4,
|
|
name: 'NonFollowerUser2',
|
|
email: 'non-follower-user2@example.com',
|
|
}];
|
|
|
|
// link followers
|
|
this.data.partner.records[0].message_follower_ids = [10, 20];
|
|
|
|
// prefetched partners
|
|
this.data.initMessaging = {
|
|
mention_partner_suggestions: [followerSuggestions.concat(nonFollowerSuggestions)],
|
|
};
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
services: this.services,
|
|
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" options="{\'display_log_button\': True}"/>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/mail/read_followers') {
|
|
return Promise.resolve({
|
|
followers: [{
|
|
id: 10,
|
|
name: 'FollowerUser1',
|
|
email: 'follower-user1@example.com',
|
|
res_model: 'res.partner',
|
|
res_id: 1,
|
|
}, {
|
|
id: 20,
|
|
name: 'FollowerUser2',
|
|
email: 'follower-user2@example.com',
|
|
res_model: 'res.partner',
|
|
res_id: 2,
|
|
}],
|
|
subtypes: [],
|
|
});
|
|
}
|
|
if (route === '/mail/get_suggested_recipients') {
|
|
return Promise.resolve({2: []});
|
|
}
|
|
if (args.method === 'get_mention_suggestions') {
|
|
throw new Error('should not fetch partners for mentions');
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
session: {},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_followers_count').text(), '2',
|
|
"should have two followers of this document");
|
|
assert.strictEqual(form.$('.o_followers_list > .o_partner').text().replace(/\s+/g, ''),
|
|
'FollowerUser1FollowerUser2',
|
|
"should have correct follower names");
|
|
assert.strictEqual(form.$('.o_composer_mention_dropdown').length, 0,
|
|
"should not show the mention suggestion dropdown");
|
|
|
|
await testUtils.dom.click(form.$('.o_chatter_button_new_message'));
|
|
var $input = form.$('.oe_chatter .o_composer_text_field:first()');
|
|
$input.val('@');
|
|
// the cursor position must be set for the mention manager to detect that we are mentionning
|
|
$input[0].selectionStart = 1;
|
|
$input[0].selectionEnd = 1;
|
|
$input.trigger('keyup');
|
|
await testUtils.nextTick();
|
|
assert.strictEqual(form.$('.o_composer_mention_dropdown').length, 1,
|
|
"should show the mention suggestion dropdown");
|
|
|
|
assert.strictEqual(form.$('.o_mention_proposition').length, 4,
|
|
"should show 4 mention suggestions");
|
|
assert.strictEqual(form.$('.o_mention_proposition').eq(0).text().replace(/\s+/g, ''),
|
|
"FollowerUser1(follower-user1@example.com)",
|
|
"should display correct 1st mention suggestion");
|
|
assert.strictEqual(form.$('.o_mention_proposition').eq(1).text().replace(/\s+/g, ''),
|
|
"FollowerUser2(follower-user2@example.com)",
|
|
"should display correct 2nd mention suggestion");
|
|
assert.ok(form.$('.o_mention_proposition').eq(1).next().hasClass('dropdown-divider'),
|
|
"should have a mention separator after last follower mention suggestion");
|
|
assert.strictEqual(form.$('.o_mention_proposition').eq(2).text().replace(/\s+/g, ''),
|
|
"NonFollowerUser1(non-follower-user1@example.com)",
|
|
"should display correct 3rd mention suggestion");
|
|
assert.strictEqual(form.$('.o_mention_proposition').eq(3).text().replace(/\s+/g, ''),
|
|
"NonFollowerUser2(non-follower-user2@example.com)",
|
|
"should display correct 4th mention suggestion");
|
|
|
|
//cleanup
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldMany2ManyTagsEmail', {
|
|
beforeEach: function () {
|
|
this.data = {
|
|
partner: {
|
|
fields: {
|
|
display_name: { string: "Displayed name", type: "char" },
|
|
timmy: { string: "pokemon", type: "many2many", relation: 'partner_type'},
|
|
},
|
|
records: [{
|
|
id: 1,
|
|
display_name: "first record",
|
|
timmy: [],
|
|
}],
|
|
},
|
|
partner_type: {
|
|
fields: {
|
|
name: {string: "Partner Type", type: "char"},
|
|
email: {string: "Email", type: "char"},
|
|
},
|
|
records: [
|
|
{id: 12, display_name: "gold", email: 'coucou@petite.perruche'},
|
|
{id: 14, display_name: "silver", email: ''},
|
|
]
|
|
},
|
|
};
|
|
},
|
|
});
|
|
|
|
QUnit.test('fieldmany2many tags email', function (assert) {
|
|
assert.expect(13);
|
|
var done = assert.async();
|
|
|
|
this.data.partner.records[0].timmy = [12, 14];
|
|
|
|
// the modals need to be closed before the form view rendering
|
|
createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
res_id: 1,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="display_name"/>' +
|
|
'<field name="timmy" widget="many2many_tags_email"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
mockRPC: function (route, args) {
|
|
if (args.method ==='read' && args.model === 'partner_type') {
|
|
assert.step(JSON.stringify(args.args[0]));
|
|
assert.deepEqual(args.args[1] , ['display_name', 'email'], "should read the email");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
archs: {
|
|
'partner_type,false,form': '<form string="Types"><field name="display_name"/><field name="email"/></form>',
|
|
},
|
|
}).then(async function (form) {
|
|
// should read it 3 times (1 with the form view, one with the form dialog and one after save)
|
|
assert.verifySteps(['[12,14]', '[14]', '[14]']);
|
|
await testUtils.nextTick();
|
|
assert.containsN(form, '.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0', 2,
|
|
"two tags should be present");
|
|
var firstTag = form.$('.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0').first();
|
|
assert.strictEqual(firstTag.find('.o_badge_text').text(), "gold",
|
|
"tag should only show display_name");
|
|
assert.hasAttrValue(firstTag.find('.o_badge_text'), 'title', "coucou@petite.perruche",
|
|
"tag should show email address on mouse hover");
|
|
form.destroy();
|
|
done();
|
|
});
|
|
testUtils.nextTick().then(function() {
|
|
assert.strictEqual($('.modal-body.o_act_window').length, 1,
|
|
"there should be one modal opened to edit the empty email");
|
|
assert.strictEqual($('.modal-body.o_act_window input[name="display_name"]').val(), "silver",
|
|
"the opened modal should be a form view dialog with the partner_type 14");
|
|
assert.strictEqual($('.modal-body.o_act_window input[name="email"]').length, 1,
|
|
"there should be an email field in the modal");
|
|
|
|
// set the email and save the modal (will render the form view)
|
|
testUtils.fields.editInput($('.modal-body.o_act_window input[name="email"]'), 'coucou@petite.perruche');
|
|
testUtils.dom.click($('.modal-footer .btn-primary'));
|
|
});
|
|
|
|
});
|
|
|
|
QUnit.test('fieldmany2many tags email (edition)', async function (assert) {
|
|
assert.expect(15);
|
|
|
|
this.data.partner.records[0].timmy = [12];
|
|
|
|
var form = await createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
res_id: 1,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="display_name"/>' +
|
|
'<field name="timmy" widget="many2many_tags_email"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
mockRPC: function (route, args) {
|
|
if (args.method ==='read' && args.model === 'partner_type') {
|
|
assert.step(JSON.stringify(args.args[0]));
|
|
assert.deepEqual(args.args[1] , ['display_name', 'email'], "should read the email");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
archs: {
|
|
'partner_type,false,form': '<form string="Types"><field name="display_name"/><field name="email"/></form>',
|
|
},
|
|
});
|
|
|
|
assert.verifySteps(['[12]']);
|
|
assert.containsOnce(form, '.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0',
|
|
"should contain one tag");
|
|
|
|
// add an other existing tag
|
|
await testUtils.fields.many2one.clickOpenDropdown('timmy');
|
|
await testUtils.fields.many2one.clickHighlightedItem('timmy');
|
|
|
|
assert.strictEqual($('.modal-body.o_act_window').length, 1,
|
|
"there should be one modal opened to edit the empty email");
|
|
assert.strictEqual($('.modal-body.o_act_window input[name="display_name"]').val(), "silver",
|
|
"the opened modal in edit mode should be a form view dialog with the partner_type 14");
|
|
assert.strictEqual($('.modal-body.o_act_window input[name="email"]').length, 1,
|
|
"there should be an email field in the modal");
|
|
|
|
// set the email and save the modal (will rerender the form view)
|
|
await testUtils.fields.editInput($('.modal-body.o_act_window input[name="email"]'), 'coucou@petite.perruche');
|
|
await testUtils.dom.click($('.modal-footer .btn-primary'));
|
|
|
|
assert.containsN(form, '.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0', 2,
|
|
"should contain the second tag");
|
|
// should have read [14] three times: when opening the dropdown, when opening the modal, and
|
|
// after the save
|
|
assert.verifySteps(['[14]', '[14]', '[14]']);
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
});
|
|
});
|