From 356a5448fe6d6e0c2e65c1c699ef357577b36e5d Mon Sep 17 00:00:00 2001 From: Xavier Dubuc Date: Fri, 4 Sep 2020 16:08:57 +0000 Subject: [PATCH] [FIX] mail: fix notification partners display in popover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle notification creation in convertData correctly. task-2324260 closes odoo/odoo#58013 X-original-commit: ca457e990c87cd0405a2b7416a6c8064a9a83e21 Signed-off-by: Sébastien Theys (seb) --- .../src/components/message/message.scss | 2 +- .../static/src/components/message/message.xml | 4 +- .../src/components/message/message_tests.js | 8 +- .../thread_view/thread_view_tests.js | 226 +++++++++++++++++- .../src/models/notification/notification.js | 2 +- .../mail/static/tests/helpers/mock_server.js | 13 +- .../src/components/message/message_tests.js | 8 +- .../src/components/message/message_tests.js | 32 +-- 8 files changed, 263 insertions(+), 32 deletions(-) diff --git a/addons/mail/static/src/components/message/message.scss b/addons/mail/static/src/components/message/message.scss index 924fa75d113..b91aacba91c 100644 --- a/addons/mail/static/src/components/message/message.scss +++ b/addons/mail/static/src/components/message/message.scss @@ -335,7 +335,7 @@ } } -.o_Message_notificationIconContainer { +.o_Message_notificationIconClickable { color: gray('600'); cursor: pointer; diff --git a/addons/mail/static/src/components/message/message.xml b/addons/mail/static/src/components/message/message.xml index d739cb1769f..a33ded5af81 100644 --- a/addons/mail/static/src/components/message/message.xml +++ b/addons/mail/static/src/components/message/message.xml @@ -94,13 +94,13 @@ - + - + diff --git a/addons/mail/static/src/components/message/message_tests.js b/addons/mail/static/src/components/message/message_tests.js index eefd6f3294d..dedc9434f2a 100644 --- a/addons/mail/static/src/components/message/message_tests.js +++ b/addons/mail/static/src/components/message/message_tests.js @@ -219,7 +219,7 @@ QUnit.test('Notification Sent', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -234,7 +234,7 @@ QUnit.test('Notification Sent', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -310,7 +310,7 @@ QUnit.test('Notification Error', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -325,7 +325,7 @@ QUnit.test('Notification Error', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.verifySteps( ['do_action'], diff --git a/addons/mail/static/src/components/thread_view/thread_view_tests.js b/addons/mail/static/src/components/thread_view/thread_view_tests.js index 3a141e751ec..d93f911e04a 100644 --- a/addons/mail/static/src/components/thread_view/thread_view_tests.js +++ b/addons/mail/static/src/components/thread_view/thread_view_tests.js @@ -46,9 +46,10 @@ QUnit.module('thread_view_tests.js', { }; this.start = async params => { - const { env, widget } = await start(Object.assign({}, params, { + const { afterEvent, env, widget } = await start(Object.assign({}, params, { data: this.data, })); + this.afterEvent = afterEvent; this.env = env; this.widget = widget; }; @@ -566,6 +567,229 @@ QUnit.test('new messages separator on receiving new message', async function (as ); }); +QUnit.test('new messages separator on posting message', async function (assert) { + assert.expect(4); + + this.data['mail.channel'].records = [{ + channel_type: 'channel', + id: 20, + is_pinned: true, + message_unread_counter: 0, + name: "General", + }]; + await this.start(); + const thread = this.env.models['mail.thread'].findFromIdentifyingData({ + id: 20, + model: 'mail.channel' + }); + const threadViewer = this.env.models['mail.thread_viewer'].create({ + hasThreadView: true, + thread: [['link', thread]], + }); + await this.createThreadViewComponent(threadViewer.threadView, { hasComposer: true }); + + assert.containsNone( + document.body, + '.o_MessageList_message', + "should have no messages" + ); + assert.containsNone( + document.body, + '.o_MessageList_separatorNewMessages', + "should not display 'new messages' separator" + ); + + document.querySelector('.o_ComposerTextInput_textarea').focus(); + await afterNextRender(() => document.execCommand('insertText', false, "hey !")); + await afterNextRender(() => + document.querySelector('.o_Composer_buttonSend').click() + ); + assert.containsOnce( + document.body, + '.o_Message', + "should have the message current partner just posted" + ); + assert.containsNone( + document.body, + '.o_MessageList_separatorNewMessages', + "still no separator shown when current partner posted a message" + ); +}); + +QUnit.test('new messages separator on receiving new message', async function (assert) { + assert.expect(6); + + this.data['res.partner'].records.push({ + id:11, + name: "Foreigner partner", + }); + this.data['res.users'].records.push({ + id: 42, + name: "Foreigner user", + partner_id: 11, + }); + this.data['mail.channel'].records.push({ + channel_type: 'channel', + id: 20, + is_pinned: true, + message_unread_counter: 0, + name: "General", + seen_message_id: 1, + uuid: 'randomuuid', + }); + this.data['mail.message'].records.push({ + body: "blah", + channel_ids: [20], + id: 1, + }); + await this.start(); + const thread = this.env.models['mail.thread'].findFromIdentifyingData({ + id: 20, + model: 'mail.channel' + }); + const threadViewer = this.env.models['mail.thread_viewer'].create({ + hasThreadView: true, + thread: [['link', thread]], + }); + await this.createThreadViewComponent(threadViewer.threadView, { hasComposer: true }); + + assert.containsOnce( + document.body, + '.o_MessageList_message', + "should have an initial message" + ); + assert.containsNone( + document.body, + '.o_MessageList_separatorNewMessages', + "should not display 'new messages' separator" + ); + + document.querySelector('.o_ComposerTextInput_textarea').blur(); + // simulate receiving a message + await afterNextRender(async () => this.env.services.rpc({ + route: '/mail/chat_post', + params: { + context: { + mockedUserId: 42, + }, + uuid: thread.uuid, + message_content: "hu", + }, + })); + assert.containsN( + document.body, + '.o_Message', + 2, + "should now have 2 messages after receiving a new message" + ); + assert.containsOnce( + document.body, + '.o_MessageList_separatorNewMessages', + "'new messages' separator should be shown" + ); + + assert.containsOnce( + document.body, + `.o_MessageList_separatorNewMessages ~ .o_Message[data-message-local-id="${ + this.env.models['mail.message'].findFromIdentifyingData({id: 2}).localId + }"]`, + "'new messages' separator should be shown above new message received" + ); + + await afterNextRender(() => document.querySelector('.o_ComposerTextInput_textarea').focus()); + assert.containsNone( + document.body, + '.o_MessageList_separatorNewMessages', + "'new messages' separator should no longer be shown as last message has been seen" + ); +}); + +QUnit.test('basic rendering of canceled notification', async function (assert) { + assert.expect(8); + + this.data['mail.channel'].records.push({ id: 11 }); + this.data['res.partner'].records.push({ id: 12, name: "Someone" }); + this.data['mail.message'].records.push({ + channel_ids: [11], + id: 10, + message_type: 'email', + model: 'mail.channel', + notification_ids: [11], + res_id: 11, + }); + this.data['mail.notification'].records.push({ + failure_type: 'SMTP', + id: 11, + mail_message_id: 10, + notification_status: 'canceled', + notification_type: 'email', + res_partner_id: 12, + }); + await this.start(); + const threadViewer = await this.env.models['mail.thread_viewer'].create({ + hasThreadView: true, + thread: [['insert', { + id: 11, + model: 'mail.channel', + }]], + }); + await this.afterEvent({ + eventName: 'o-component-message-list-thread-cache-changed', + func: () => { + this.createThreadViewComponent(threadViewer.threadView); + }, + message: "thread become loaded with messages", + predicate: ({ threadViewer }) => { + return threadViewer.thread.model === 'mail.channel' && threadViewer.thread.id === 11; + }, + }); + + assert.containsOnce( + document.body, + '.o_Message_notificationIconClickable', + "should display the notification icon container on the message" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIcon', + "should display the notification icon on the message" + ); + assert.hasClass( + document.querySelector('.o_Message_notificationIcon'), + 'fa-envelope-o', + "notification icon shown on the message should represent email" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconClickable').click(); + }); + assert.containsOnce( + document.body, + '.o_NotificationPopover', + "notification popover should be opened after notification has been clicked" + ); + assert.containsOnce( + document.body, + '.o_NotificationPopover_notificationIcon', + "an icon should be shown in notification popover" + ); + assert.containsOnce( + document.body, + '.o_NotificationPopover_notificationIcon.fa.fa-trash-o', + "the icon shown in notification popover should be the canceled icon" + ); + assert.containsOnce( + document.body, + '.o_NotificationPopover_notificationPartnerName', + "partner name should be shown in notification popover" + ); + assert.strictEqual( + document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(), + "Someone", + "partner name shown in notification popover should be the one concerned by the notification" + ); +}); + }); }); }); diff --git a/addons/mail/static/src/models/notification/notification.js b/addons/mail/static/src/models/notification/notification.js index fadc874de73..047faee95b8 100644 --- a/addons/mail/static/src/models/notification/notification.js +++ b/addons/mail/static/src/models/notification/notification.js @@ -32,7 +32,7 @@ function factory(dependencies) { data2.notification_type = data.notification_type; } if ('res_partner_id' in data) { - if (!data.partner_id) { + if (!data.res_partner_id) { data2.partner = [['unlink-all']]; } else { data2.partner = [ diff --git a/addons/mail/static/tests/helpers/mock_server.js b/addons/mail/static/tests/helpers/mock_server.js index 5da2d6e52a3..a58a685040c 100644 --- a/addons/mail/static/tests/helpers/mock_server.js +++ b/addons/mail/static/tests/helpers/mock_server.js @@ -1079,20 +1079,27 @@ MockServer.include({ 'res_model': attachment.res_model, }); }); - const notifications = this._getRecords('mail.notification', [ + const allNotifications = this._getRecords('mail.notification', [ ['mail_message_id', '=', message.id], ]); - const historyPartnerIds = notifications + const historyPartnerIds = allNotifications .filter(notification => notification.is_read) .map(notification => notification.res_partner_id); - const needactionPartnerIds = notifications + const needactionPartnerIds = allNotifications .filter(notification => !notification.is_read) .map(notification => notification.res_partner_id); + let notifications = this._mockMailNotification_FilteredForWebClient( + allNotifications.map(notification => notification.id) + ); + notifications = this._mockMailNotification_NotificationFormat( + notifications.map(notification => notification.id) + ); return Object.assign({}, message, { attachment_ids: formattedAttachments, author_id: formattedAuthor, history_partner_ids: historyPartnerIds, needaction_partner_ids: needactionPartnerIds, + notifications, }); }); }, diff --git a/addons/sms/static/src/components/message/message_tests.js b/addons/sms/static/src/components/message/message_tests.js index 4eff0ae768c..d0670e2113f 100644 --- a/addons/sms/static/src/components/message/message_tests.js +++ b/addons/sms/static/src/components/message/message_tests.js @@ -75,7 +75,7 @@ QUnit.test('Notification Sent', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -90,7 +90,7 @@ QUnit.test('Notification Sent', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -166,7 +166,7 @@ QUnit.test('Notification Error', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -181,7 +181,7 @@ QUnit.test('Notification Error', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.verifySteps( ['do_action'], diff --git a/addons/snailmail/static/src/components/message/message_tests.js b/addons/snailmail/static/src/components/message/message_tests.js index f4dde33e651..69c16c571f5 100644 --- a/addons/snailmail/static/src/components/message/message_tests.js +++ b/addons/snailmail/static/src/components/message/message_tests.js @@ -74,7 +74,7 @@ QUnit.test('Sent', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -89,7 +89,7 @@ QUnit.test('Sent', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -145,7 +145,7 @@ QUnit.test('Canceled', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -160,7 +160,7 @@ QUnit.test('Canceled', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -216,7 +216,7 @@ QUnit.test('Pending', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -231,7 +231,7 @@ QUnit.test('Pending', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -295,7 +295,7 @@ QUnit.test('No Price Available', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -310,7 +310,7 @@ QUnit.test('No Price Available', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -382,7 +382,7 @@ QUnit.test('Credit Error', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -397,7 +397,7 @@ QUnit.test('Credit Error', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -474,7 +474,7 @@ QUnit.test('Trial Error', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -489,7 +489,7 @@ QUnit.test('Trial Error', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.containsOnce( document.body, @@ -574,7 +574,7 @@ QUnit.test('Format Error', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -589,7 +589,7 @@ QUnit.test('Format Error', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.verifySteps( ['do_action'], @@ -650,7 +650,7 @@ QUnit.test('Missing Required Fields', async function (assert) { ); assert.containsOnce( document.body, - '.o_Message_notificationIconContainer', + '.o_Message_notificationIconClickable', "should display the notification icon container" ); assert.containsOnce( @@ -665,7 +665,7 @@ QUnit.test('Missing Required Fields', async function (assert) { ); await afterNextRender(() => { - document.querySelector('.o_Message_notificationIconContainer').click(); + document.querySelector('.o_Message_notificationIconClickable').click(); }); assert.verifySteps( ['do_action'],