summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
diff options
context:
space:
mode:
authorSébastien Theys <seb@odoo.com>2020-06-15 18:12:21 +0000
committerSébastien Theys <seb@odoo.com>2020-06-15 18:12:21 +0000
commit3fea5b2136627c1d7e83b2a5e111952fe3eb10a1 (patch)
tree5eefad07972a87ce4689b83260f981bc87aadad4 /addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
parent0a82848606151ef60eb6523e9c4c161171f214e7 (diff)
[REF] mail, *: refactor messaging with OWL
This commit is a significant rewriting of client-side discuss, chatter, chat window, and messaging menu using OWL. The behavior should be broadly the same, with some slight functional changes here and there. From a technical standpoint, the code of messaging is mainly organized in 2 main groups of modules: - models, which are logical entities that depict the client-side state of messaging as a whole. - components, which are in charge of displaying information from models. This refactoring also introduces new JS guidelines regarding folder structure (/static) and naming rules for JS modules. Community PR: https://github.com/odoo/odoo/pull/39023 Enterprise PR: https://github.com/odoo/enterprise/pull/6249 Task-1914207 This PR is a collaborative work by Alexandre, Julien, Sébastien and Xavier, with the precious help of Lucas to speed it up towards the end. closes odoo/odoo#39023 Related: odoo/enterprise#6249 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Co-authored-by: Alexandre Kühn <aku@odoo.com> Co-authored-by: Julien Giannone <jgi@odoo.com> Co-authored-by: Lucas Perais <lpe@odoo.com> Co-authored-by: Sébastien Theys <seb@odoo.com> Co-authored-by: Xavier Dubuc <xdu@odoo.com>
Diffstat (limited to 'addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js')
-rw-r--r--addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js849
1 files changed, 849 insertions, 0 deletions
diff --git a/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js b/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
new file mode 100644
index 00000000000..60159360899
--- /dev/null
+++ b/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
@@ -0,0 +1,849 @@
+odoo.define('mail/static/src/components/messaging_menu/messaging_menu_tests.js', function (require) {
+'use strict';
+
+const {
+ afterEach: utilsAfterEach,
+ afterNextRender,
+ beforeEach: utilsBeforeEach,
+ start: utilsStart,
+} = require('mail/static/src/utils/test_utils.js');
+
+const { makeTestPromise } = require('web.test_utils');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('messaging_menu', {}, function () {
+QUnit.module('messaging_menu_tests.js', {
+ beforeEach() {
+ utilsBeforeEach(this);
+
+ this.start = async params => {
+ if (this.widget) {
+ this.widget.destroy();
+ }
+ let { discussWidget, env, widget } = await utilsStart(Object.assign({}, params, {
+ data: this.data,
+ hasMessagingMenu: true,
+ }));
+ this.discussWidget = discussWidget;
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ utilsAfterEach(this);
+ if (this.widget) {
+ this.widget.destroy();
+ }
+ },
+});
+
+QUnit.test('messaging not initialized', async function (assert) {
+ assert.expect(2);
+
+ await this.start({
+ async mockRPC(route) {
+ if (route === '/mail/init_messaging') {
+ // simulate messaging never initialized
+ return new Promise(resolve => {});
+ }
+ return this._super(...arguments);
+ },
+ waitUntilMessagingInitialized: false,
+ });
+ assert.strictEqual(
+ document.querySelectorAll('.o_MessagingMenu_loading').length,
+ 1,
+ "should display loading icon on messaging menu when messaging not yet initialized"
+ );
+
+ await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click());
+ assert.strictEqual(
+ document.querySelector('.o_MessagingMenu_dropdownMenu').textContent,
+ "Please wait...",
+ "should prompt loading when opening messaging menu"
+ );
+});
+
+QUnit.test('messaging becomes initialized', async function (assert) {
+ assert.expect(2);
+
+ const messagingInitializedProm = makeTestPromise();
+
+ await this.start({
+ async mockRPC(route) {
+ const _super = this._super.bind(this, ...arguments); // limitation of class.js
+ if (route === '/mail/init_messaging') {
+ await messagingInitializedProm;
+ }
+ return _super();
+ },
+ waitUntilMessagingInitialized: false,
+ });
+ await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click());
+
+ // simulate messaging becomes initialized
+ await afterNextRender(() => messagingInitializedProm.resolve());
+ assert.strictEqual(
+ document.querySelectorAll('.o_MessagingMenu_loading').length,
+ 0,
+ "should no longer display loading icon on messaging menu when messaging becomes initialized"
+ );
+ assert.notOk(
+ document.querySelector('.o_MessagingMenu_dropdownMenu').textContent.includes("Please wait..."),
+ "should no longer prompt loading when opening messaging menu when messaging becomes initialized"
+ );
+});
+
+QUnit.test('basic rendering', async function (assert) {
+ assert.expect(21);
+
+ await this.start({
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [];
+ }
+ return this._super(...arguments);
+ },
+ });
+ assert.strictEqual(
+ document.querySelectorAll('.o_MessagingMenu').length,
+ 1,
+ "should have messaging menu"
+ );
+ assert.notOk(
+ document.querySelector('.o_MessagingMenu').classList.contains('show'),
+ "should not mark messaging menu item as shown by default"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_toggler`).length,
+ 1,
+ "should have clickable element on messaging menu"
+ );
+ assert.notOk(
+ document.querySelector(`.o_MessagingMenu_toggler`).classList.contains('show'),
+ "should not mark messaging menu clickable item as shown by default"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_icon`).length,
+ 1,
+ "should have icon on clickable element in messaging menu"
+ );
+ assert.ok(
+ document.querySelector(`.o_MessagingMenu_icon`).classList.contains('fa-comments-o'),
+ "should have 'comments' icon on clickable element in messaging menu"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_dropdownMenu`).length,
+ 0,
+ "should not display any messaging menu dropdown by default"
+ );
+
+ await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click());
+ assert.ok(
+ document.querySelector('.o_MessagingMenu').classList.contains('show'),
+ "should mark messaging menu item as shown"
+ );
+ assert.ok(
+ document.querySelector(`.o_MessagingMenu_toggler`).classList.contains('show'),
+ "should mark messaging menu clickable item as shown"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_dropdownMenu`).length,
+ 1,
+ "should display messaging menu dropdown after click"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_dropdownMenuHeader`).length,
+ 1,
+ "should have dropdown menu header"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenuHeader
+ .o_MessagingMenu_tabButton
+ `).length,
+ 3,
+ "should have 3 tab buttons to filter items in the header"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_tabButton[data-tab-id="all"]`).length,
+ 1,
+ "1 tab button should be 'All'"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_tabButton[data-tab-id="chat"]`).length,
+ 1,
+ "1 tab button should be 'Chat'"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_tabButton[data-tab-id="channel"]`).length,
+ 1,
+ "1 tab button should be 'Channels'"
+ );
+ assert.ok(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="all"]
+ `).classList.contains('o-active'),
+ "'all' tab button should be active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="chat"]
+ `).classList.contains('o-active'),
+ "'chat' tab button should not be active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="channel"]
+ `).classList.contains('o-active'),
+ "'channel' tab button should not be active"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_newMessageButton`).length,
+ 1,
+ "should have button to make a new message"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_NotificationList
+ `).length,
+ 1,
+ "should display thread preview list"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_NotificationList_noConversation
+ `).length,
+ 1,
+ "should display no conversation in thread preview list"
+ );
+});
+
+QUnit.test('counter is taking into account failure notification', async function (assert) {
+ assert.expect(2);
+
+ this.data.initMessaging.mail_failures = [{
+ date: moment.utc().format("YYYY-MM-DD HH:mm:ss"),
+ id: 11,
+ message_type: 'email',
+ model: 'mail.channel',
+ notifications: [{
+ failure_type: 'SMTP',
+ id: 21,
+ notification_status: 'exception',
+ notification_type: 'email',
+ partner_id: [41, "Someone"],
+ }],
+ res_id: 31,
+ res_model_name: "Channel",
+ }];
+ await this.start();
+
+ assert.containsOnce(
+ document.body,
+ '.o_MessagingMenu_counter',
+ "should display a notification counter next to the messaging menu for one notification"
+ );
+ assert.strictEqual(
+ document.querySelector('.o_MessagingMenu_counter').textContent,
+ "1",
+ "should display a counter of '1' next to the messaging menu"
+ );
+});
+
+QUnit.test('switch tab', async function (assert) {
+ assert.expect(15);
+
+ await this.start({
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [];
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click());
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_tabButton[data-tab-id="all"]`).length,
+ 1,
+ "1 tab button should be 'All'"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_tabButton[data-tab-id="chat"]`).length,
+ 1,
+ "1 tab button should be 'Chat'"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_tabButton[data-tab-id="channel"]`).length,
+ 1,
+ "1 tab button should be 'Channels'"
+ );
+ assert.ok(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="all"]
+ `).classList.contains('o-active'),
+ "'all' tab button should be active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="chat"]
+ `).classList.contains('o-active'),
+ "'chat' tab button should not be active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="channel"]
+ `).classList.contains('o-active'),
+ "'channel' tab button should not be active"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_tabButton[data-tab-id="chat"]`).click()
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="all"]
+ `).classList.contains('o-active'),
+ "'all' tab button should become inactive"
+ );
+ assert.ok(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="chat"]
+ `).classList.contains('o-active'),
+ "'chat' tab button should not become active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="channel"]
+ `).classList.contains('o-active'),
+ "'channel' tab button should stay inactive"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_tabButton[data-tab-id="channel"]`).click()
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="all"]
+ `).classList.contains('o-active'),
+ "'all' tab button should stay active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="chat"]
+ `).classList.contains('o-active'),
+ "'chat' tab button should become inactive"
+ );
+ assert.ok(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="channel"]
+ `).classList.contains('o-active'),
+ "'channel' tab button should become active"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_tabButton[data-tab-id="all"]`).click()
+ );
+ assert.ok(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="all"]
+ `).classList.contains('o-active'),
+ "'all' tab button should become active"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="chat"]
+ `).classList.contains('o-active'),
+ "'chat' tab button should stay inactive"
+ );
+ assert.notOk(
+ document.querySelector(`
+ .o_MessagingMenu_tabButton[data-tab-id="channel"]
+ `).classList.contains('o-active'),
+ "'channel' tab button should become inactive"
+ );
+});
+
+QUnit.test('new message', async function (assert) {
+ assert.expect(3);
+
+ await this.start({
+ hasChatWindow: true,
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [];
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_toggler`).click()
+ );
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_newMessageButton`).click()
+ );
+
+ assert.strictEqual(
+ document.querySelectorAll(`.o_ChatWindow`).length,
+ 1,
+ "should have open a chat window"
+ );
+ assert.ok(
+ document.querySelector(`.o_ChatWindow`).classList.contains('o-new-message'),
+ "chat window should be for new message"
+ );
+ assert.ok(
+ document.querySelector(`.o_ChatWindow`).classList.contains('o-focused'),
+ "chat window should be focused"
+ );
+});
+
+QUnit.test('no new message when discuss is open', async function (assert) {
+ assert.expect(3);
+
+ await this.start({
+ autoOpenDiscuss: true,
+ hasDiscuss: true,
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [];
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_toggler`).click()
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_newMessageButton`).length,
+ 0,
+ "should not have 'new message' when discuss is open"
+ );
+
+ // simulate closing discuss app
+ await afterNextRender(() => this.discussWidget.on_detach_callback());
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_newMessageButton`).length,
+ 1,
+ "should have 'new message' when discuss is closed"
+ );
+
+ // simulate opening discuss app
+ await afterNextRender(() => this.discussWidget.on_attach_callback());
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_newMessageButton`).length,
+ 0,
+ "should not have 'new message' when discuss is open again"
+ );
+});
+
+QUnit.test('channel preview: basic rendering', async function (assert) {
+ assert.expect(9);
+
+ Object.assign(this.data.initMessaging, {
+ channel_slots: {
+ channel_channel: [{
+ channel_type: "channel",
+ id: 20,
+ name: "General",
+ }],
+ },
+ });
+ await this.start({
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [{
+ id: 20,
+ last_message: {
+ author_id: [7, "Demo"],
+ body: "<p>test</p>",
+ channel_ids: [20],
+ id: 100,
+ message_type: 'comment',
+ model: 'mail.channel',
+ record_name: "General",
+ res_id: 20,
+ },
+ }];
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click());
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu .o_ThreadPreview
+ `).length,
+ 1,
+ "should have one preview"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_sidebar
+ `).length,
+ 1,
+ "preview should have a sidebar"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_content
+ `).length,
+ 1,
+ "preview should have some content"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_header
+ `).length,
+ 1,
+ "preview should have header in content"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_header
+ .o_ThreadPreview_name
+ `).length,
+ 1,
+ "preview should have name in header of content"
+ );
+ assert.strictEqual(
+ document.querySelector(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_name
+ `).textContent,
+ "General", "preview should have name of channel"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_content
+ .o_ThreadPreview_core
+ `).length,
+ 1,
+ "preview should have core in content"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_core
+ .o_ThreadPreview_inlineText
+ `).length,
+ 1,
+ "preview should have inline text in core of content"
+ );
+ assert.strictEqual(
+ document.querySelector(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview_core
+ .o_ThreadPreview_inlineText
+ `).textContent.trim(),
+ "Demo: test",
+ "preview should have message content as inline text of core content"
+ );
+});
+
+QUnit.test('filtered previews', async function (assert) {
+ assert.expect(12);
+
+ Object.assign(this.data.initMessaging, {
+ channel_slots: {
+ channel_channel: [{
+ channel_type: "channel",
+ id: 20,
+ name: "General",
+ }],
+ channel_direct_message: [{
+ channel_type: "chat",
+ direct_partner: [{
+ id: 7,
+ name: "Demo",
+ }],
+ id: 10,
+ }],
+ },
+ });
+ await this.start({
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [{
+ id: 20,
+ last_message: {
+ author_id: [7, "Demo"],
+ body: "<p>test</p>",
+ channel_ids: [20],
+ id: 100,
+ message_type: 'comment',
+ model: 'mail.channel',
+ res_id: 20,
+ },
+ }, {
+ id: 10,
+ last_message: {
+ author_id: [7, "Demo"],
+ body: "<p>test2</p>",
+ channel_ids: [10],
+ id: 101,
+ message_type: 'comment',
+ model: 'mail.channel',
+ res_id: 10,
+ },
+ }];
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_toggler`).click()
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_dropdownMenu .o_ThreadPreview`).length,
+ 2,
+ "should have 2 previews"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 10 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 1,
+ "should have preview of chat"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 20 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 1,
+ "should have preview of channel"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector('.o_MessagingMenu_tabButton[data-tab-id="chat"]').click()
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_dropdownMenu .o_ThreadPreview`).length,
+ 1,
+ "should have one preview"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 10 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 1,
+ "should have preview of chat"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 20 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 0,
+ "should not have preview of channel"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector('.o_MessagingMenu_tabButton[data-tab-id="channel"]').click()
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview
+ `).length,
+ 1,
+ "should have one preview"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 10 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 0,
+ "should not have preview of chat"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 20 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 1,
+ "should have preview of channel"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector('.o_MessagingMenu_tabButton[data-tab-id="all"]').click()
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_MessagingMenu_dropdownMenu .o_ThreadPreview`).length,
+ 2,
+ "should have 2 previews"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 10 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 1,
+ "should have preview of chat"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`
+ .o_MessagingMenu_dropdownMenu
+ .o_ThreadPreview[data-thread-local-id="${
+ this.env.models['mail.thread'].find(thread =>
+ thread.id === 20 &&
+ thread.model === 'mail.channel'
+ ).localId
+ }"]
+ `).length,
+ 1,
+ "should have preview of channel"
+ );
+});
+
+QUnit.test('open chat window from preview', async function (assert) {
+ assert.expect(1);
+
+ Object.assign(this.data.initMessaging, {
+ channel_slots: {
+ channel_channel: [{
+ channel_type: "channel",
+ id: 20,
+ name: "General",
+ }],
+ },
+ });
+ await this.start({
+ hasChatWindow: true,
+ async mockRPC(route, args) {
+ if (args.method === 'channel_fetch_preview') {
+ return [];
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_toggler`).click()
+ );
+ await afterNextRender(() =>
+ document.querySelector(`.o_MessagingMenu_dropdownMenu .o_ThreadPreview`).click()
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_ChatWindow`).length,
+ 1,
+ "should have open a chat window"
+ );
+});
+
+QUnit.test('no code injection in message body preview', async function (assert) {
+ assert.expect(5);
+
+ Object.assign(this.data.initMessaging, {
+ channel_slots: {
+ channel_channel: [{
+ channel_type: "channel",
+ id: 1,
+ name: "General",
+ }],
+ },
+ });
+
+ this.data['mail.channel'].records = [{
+ id: 1,
+ name: "general",
+ channel_type: "channel",
+ channel_message_ids: [1],
+ }];
+ this.data['mail.message'].records = [{
+ id: 1,
+ author_id: [1, 'Georges'],
+ body: "<p><em>&shoulnotberaised</em><script>throw new Error('CodeInjectionError');</script></p>",
+ channel_ids: [1],
+ }];
+
+ await this.start();
+
+ await afterNextRender(() => {
+ document.querySelector(`.o_MessagingMenu_toggler`).click();
+ });
+ assert.containsOnce(
+ document.body,
+ '.o_MessagingMenu_dropdownMenu .o_ThreadPreview',
+ "should display a preview",
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ThreadPreview_core',
+ "preview should have core in content",
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ThreadPreview_inlineText',
+ "preview should have inline text in core of content",
+ );
+ assert.strictEqual(
+ document.querySelector('.o_ThreadPreview_inlineText')
+ .textContent.replace(/\s/g, ""),
+ "Georges:&shoulnotberaisedthrownewError('CodeInjectionError');",
+ "should display correct uninjected last message inline content"
+ );
+ assert.containsNone(
+ document.querySelector('.o_ThreadPreview_inlineText'),
+ 'script',
+ "last message inline content should not have any code injection"
+ );
+});
+
+});
+});
+});
+
+});