diff --git a/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview.xml b/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview.xml
index 82612ed233c..ebdab785bba 100644
--- a/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview.xml
+++ b/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview.xml
@@ -48,7 +48,7 @@
-
+
diff --git a/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js b/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js
new file mode 100644
index 00000000000..e65d470f2b6
--- /dev/null
+++ b/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js
@@ -0,0 +1,100 @@
+odoo.define('mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js', function (require) {
+'use strict';
+
+const components = {
+ ThreadNeedactionPreview: require('mail/static/src/components/thread_needaction_preview/thread_needaction_preview.js'),
+};
+
+const {
+ afterEach: utilsAfterEach,
+ afterNextRender,
+ beforeEach: utilsBeforeEach,
+ start: utilsStart,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('thread_needaction_preview', {}, function () {
+QUnit.module('thread_needaction_preview_tests.js', {
+ beforeEach() {
+ utilsBeforeEach(this);
+
+ this.createThreadNeedactionPreviewComponent = async props => {
+ const ThreadNeedactionPreviewComponent = components.ThreadNeedactionPreview;
+ ThreadNeedactionPreviewComponent.env = this.env;
+ this.component = new ThreadNeedactionPreviewComponent(null, props);
+ delete ThreadNeedactionPreviewComponent.env;
+ await afterNextRender(() => this.component.mount(this.widget.el));
+ };
+
+ this.start = async params => {
+ let { env, widget } = await utilsStart(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ utilsAfterEach(this);
+ if (this.component) {
+ this.component.destroy();
+ this.component = undefined;
+ }
+ if (this.widget) {
+ this.widget.destroy();
+ this.widget = undefined;
+ }
+ this.env = undefined;
+ },
+});
+
+QUnit.test('mark as read', async function (assert) {
+ assert.expect(4);
+
+ await this.start({
+ hasChatWindow: true,
+ async mockRPC(route, args) {
+ if (route.includes('set_message_done')) {
+ assert.step('set_message_done');
+ }
+ return this._super(...arguments);
+ },
+ });
+ const thread = this.env.models['mail.thread'].create({
+ id: 11,
+ model: 'mail.channel',
+ });
+ this.env.models['mail.message'].create({
+ id: 21,
+ isNeedaction: true,
+ originThread: [['link', thread]],
+ });
+ await this.createThreadNeedactionPreviewComponent({
+ threadLocalId: thread.localId,
+ });
+ assert.containsOnce(
+ document.body,
+ '.o_ThreadNeedactionPreview_markAsRead',
+ "should have 1 mark as read button"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector('.o_ThreadNeedactionPreview_markAsRead').click()
+ );
+ assert.verifySteps(
+ ['set_message_done'],
+ "should have marked the message as read"
+ );
+ assert.containsNone(
+ document.body,
+ '.o_ChatWindow',
+ "should not have opened the thread"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/mail/static/src/components/thread_preview/thread_preview.xml b/addons/mail/static/src/components/thread_preview/thread_preview.xml
index ded9c6fadac..8b067a5ae6f 100644
--- a/addons/mail/static/src/components/thread_preview/thread_preview.xml
+++ b/addons/mail/static/src/components/thread_preview/thread_preview.xml
@@ -52,7 +52,7 @@
-
+
diff --git a/addons/mail/static/src/components/thread_preview/thread_preview_tests.js b/addons/mail/static/src/components/thread_preview/thread_preview_tests.js
new file mode 100644
index 00000000000..b34ce6cd3ad
--- /dev/null
+++ b/addons/mail/static/src/components/thread_preview/thread_preview_tests.js
@@ -0,0 +1,94 @@
+odoo.define('mail/static/src/components/thread_preview/thread_preview_tests.js', function (require) {
+'use strict';
+
+const components = {
+ ThreadPreview: require('mail/static/src/components/thread_preview/thread_preview.js'),
+};
+
+const {
+ afterEach: utilsAfterEach,
+ afterNextRender,
+ beforeEach: utilsBeforeEach,
+ start: utilsStart,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('thread_preview', {}, function () {
+QUnit.module('thread_preview_tests.js', {
+ beforeEach() {
+ utilsBeforeEach(this);
+
+ this.createThreadPreviewComponent = async props => {
+ const ThreadPreviewComponent = components.ThreadPreview;
+ ThreadPreviewComponent.env = this.env;
+ this.component = new ThreadPreviewComponent(null, props);
+ delete ThreadPreviewComponent.env;
+ await afterNextRender(() => this.component.mount(this.widget.el));
+ };
+
+ this.start = async params => {
+ let { env, widget } = await utilsStart(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ utilsAfterEach(this);
+ if (this.component) {
+ this.component.destroy();
+ this.component = undefined;
+ }
+ if (this.widget) {
+ this.widget.destroy();
+ this.widget = undefined;
+ }
+ this.env = undefined;
+ },
+});
+
+QUnit.test('mark as read', async function (assert) {
+ assert.expect(4);
+
+ await this.start({
+ hasChatWindow: true,
+ async mockRPC(route, args) {
+ if (route.includes('channel_seen')) {
+ assert.step('channel_seen');
+ }
+ return this._super(...arguments);
+ },
+ });
+ const thread = this.env.models['mail.thread'].create({
+ id: 11,
+ message_unread_counter: 1,
+ model: 'mail.channel',
+ });
+ await this.createThreadPreviewComponent({ threadLocalId: thread.localId });
+ assert.containsOnce(
+ document.body,
+ '.o_ThreadPreview_markAsRead',
+ "should have 1 mark as read button"
+ );
+
+ await afterNextRender(() =>
+ document.querySelector('.o_ThreadPreview_markAsRead').click()
+ );
+ assert.verifySteps(
+ ['channel_seen'],
+ "should have marked the thread as seen"
+ );
+ assert.containsNone(
+ document.body,
+ '.o_ChatWindow',
+ "should not have opened the thread"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/mail/views/assets.xml b/addons/mail/views/assets.xml
index 46770b45fc1..027b4a5acda 100644
--- a/addons/mail/views/assets.xml
+++ b/addons/mail/views/assets.xml
@@ -258,6 +258,8 @@
+
+