summaryrefslogtreecommitdiff
path: root/addons/sms/static/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'addons/sms/static/src/components')
-rw-r--r--addons/sms/static/src/components/message/message.xml20
-rw-r--r--addons/sms/static/src/components/message/message_tests.js197
-rw-r--r--addons/sms/static/src/components/notification_group/notification_group.js27
-rw-r--r--addons/sms/static/src/components/notification_group/notification_group.xml12
-rw-r--r--addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js309
5 files changed, 565 insertions, 0 deletions
diff --git a/addons/sms/static/src/components/message/message.xml b/addons/sms/static/src/components/message/message.xml
new file mode 100644
index 00000000..b8b6a18d
--- /dev/null
+++ b/addons/sms/static/src/components/message/message.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+ <t t-inherit="mail.Message" t-inherit-mode="extension">
+ <xpath expr="//*[@name='failureIcon']" position="replace">
+ <t t-if="message.message_type === 'sms'">
+ <i class="o_Message_notificationIcon fa fa-mobile"/> SMS
+ </t>
+ <t t-else="">$0</t>
+ </xpath>
+
+ <xpath expr="//*[@name='notificationIcon']" position="replace">
+ <t t-if="message.message_type === 'sms'">
+ <i class="o_Message_notificationIcon fa fa-mobile"/> SMS
+ </t>
+ <t t-else="">$0</t>
+ </xpath>
+ </t>
+
+</templates>
diff --git a/addons/sms/static/src/components/message/message_tests.js b/addons/sms/static/src/components/message/message_tests.js
new file mode 100644
index 00000000..57bc21ab
--- /dev/null
+++ b/addons/sms/static/src/components/message/message_tests.js
@@ -0,0 +1,197 @@
+odoo.define('sms/static/src/components/message/message_tests.js', function (require) {
+'use strict';
+
+const components = {
+ Message: require('mail/static/src/components/message/message.js'),
+};
+const { makeDeferred } = require('mail/static/src/utils/deferred/deferred.js');
+const {
+ afterEach,
+ afterNextRender,
+ beforeEach,
+ createRootComponent,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+const Bus = require('web.Bus');
+
+QUnit.module('sms', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('message', {}, function () {
+QUnit.module('message_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ this.createMessageComponent = async (message, otherProps) => {
+ const props = Object.assign({ messageLocalId: message.localId }, otherProps);
+ await createRootComponent(this, components.Message, {
+ props,
+ target: this.widget.el,
+ });
+ };
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('Notification Sent', async function (assert) {
+ assert.expect(9);
+
+ await this.start();
+ const threadViewer = this.env.models['mail.thread_viewer'].create({
+ hasThreadView: true,
+ thread: [['create', {
+ id: 11,
+ model: 'mail.channel',
+ }]],
+ });
+ const message = this.env.models['mail.message'].create({
+ id: 10,
+ message_type: 'sms',
+ notifications: [['insert', {
+ id: 11,
+ notification_status: 'sent',
+ notification_type: 'sms',
+ partner: [['insert', { id: 12, name: "Someone" }]],
+ }]],
+ originThread: [['link', threadViewer.thread]]
+ });
+ await this.createMessageComponent(message, {
+ threadViewLocalId: threadViewer.threadView.localId
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_Message',
+ "should display a message component"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIconClickable',
+ "should display the notification icon container"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIcon',
+ "should display the notification icon"
+ );
+ assert.hasClass(
+ document.querySelector('.o_Message_notificationIcon'),
+ 'fa-mobile',
+ "icon should represent sms"
+ );
+
+ await afterNextRender(() => {
+ document.querySelector('.o_Message_notificationIconClickable').click();
+ });
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationPopover',
+ "notification popover should be open"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationPopover_notificationIcon',
+ "popover should have one icon"
+ );
+ assert.hasClass(
+ document.querySelector('.o_NotificationPopover_notificationIcon'),
+ 'fa-check',
+ "popover should have the sent icon"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationPopover_notificationPartnerName',
+ "popover should have the partner name"
+ );
+ assert.strictEqual(
+ document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(),
+ "Someone",
+ "partner name should be correct"
+ );
+});
+
+QUnit.test('Notification Error', async function (assert) {
+ assert.expect(8);
+
+ const openResendActionDef = makeDeferred();
+ const bus = new Bus();
+ bus.on('do-action', null, payload => {
+ assert.step('do_action');
+ assert.strictEqual(
+ payload.action,
+ 'sms.sms_resend_action',
+ "action should be the one to resend sms"
+ );
+ assert.strictEqual(
+ payload.options.additional_context.default_mail_message_id,
+ 10,
+ "action should have correct message id"
+ );
+ openResendActionDef.resolve();
+ });
+
+ await this.start({ env: { bus } });
+ const threadViewer = this.env.models['mail.thread_viewer'].create({
+ hasThreadView: true,
+ thread: [['create', {
+ id: 11,
+ model: 'mail.channel',
+ }]],
+ });
+ const message = this.env.models['mail.message'].create({
+ id: 10,
+ message_type: 'sms',
+ notifications: [['insert', {
+ id: 11,
+ notification_status: 'exception',
+ notification_type: 'sms',
+ }]],
+ originThread: [['link', threadViewer.thread]]
+ });
+ await this.createMessageComponent(message, {
+ threadViewLocalId: threadViewer.threadView.localId
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_Message',
+ "should display a message component"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIconClickable',
+ "should display the notification icon container"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_Message_notificationIcon',
+ "should display the notification icon"
+ );
+ assert.hasClass(
+ document.querySelector('.o_Message_notificationIcon'),
+ 'fa-mobile',
+ "icon should represent sms"
+ );
+ document.querySelector('.o_Message_notificationIconClickable').click();
+ await openResendActionDef;
+ assert.verifySteps(
+ ['do_action'],
+ "should do an action to display the resend sms dialog"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/sms/static/src/components/notification_group/notification_group.js b/addons/sms/static/src/components/notification_group/notification_group.js
new file mode 100644
index 00000000..053fedc5
--- /dev/null
+++ b/addons/sms/static/src/components/notification_group/notification_group.js
@@ -0,0 +1,27 @@
+odoo.define('sms/static/src/components/notification_group/notification_group.js', function (require) {
+'use strict';
+
+const components = {
+ NotificationGroup: require('mail/static/src/components/notification_group/notification_group.js'),
+};
+
+const { patch } = require('web.utils');
+
+patch(components.NotificationGroup, 'sms/static/src/components/notification_group/notification_group.js', {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ image() {
+ if (this.group.notification_type === 'sms') {
+ return '/sms/static/img/sms_failure.svg';
+ }
+ return this._super(...arguments);
+ },
+});
+
+});
diff --git a/addons/sms/static/src/components/notification_group/notification_group.xml b/addons/sms/static/src/components/notification_group/notification_group.xml
new file mode 100644
index 00000000..c5f5a8db
--- /dev/null
+++ b/addons/sms/static/src/components/notification_group/notification_group.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+ <t t-inherit="mail.NotificationGroup" t-inherit-mode="extension">
+ <xpath expr="//*[hasclass('o_NotificationGroup_inlineText')]" position="inside">
+ <t t-if="group.notification_type === 'sms'">
+ An error occurred when sending an SMS.
+ </t>
+ </xpath>
+ </t>
+
+</templates>
diff --git a/addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js b/addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js
new file mode 100644
index 00000000..bd5d8402
--- /dev/null
+++ b/addons/sms/static/src/components/notification_list/notification_list_notification_group_tests.js
@@ -0,0 +1,309 @@
+odoo.define('sms/static/src/components/notification_list/notification_list_notification_group_tests.js', function (require) {
+'use strict';
+
+const components = {
+ NotificationList: require('mail/static/src/components/notification_list/notification_list.js'),
+};
+
+const {
+ afterEach,
+ beforeEach,
+ createRootComponent,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+const Bus = require('web.Bus');
+
+QUnit.module('sms', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('notification_list', {}, function () {
+QUnit.module('notification_list_notification_group_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ /**
+ * @param {Object} param0
+ * @param {string} [param0.filter='all']
+ */
+ this.createNotificationListComponent = async ({ filter = 'all' } = {}) => {
+ await createRootComponent(this, components.NotificationList, {
+ props: { filter },
+ target: this.widget.el,
+ });
+ };
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('mark as read', async function (assert) {
+ assert.expect(6);
+
+ this.data['mail.message'].records.push(
+ // message that is expected to have a failure
+ {
+ id: 11, // random unique id, will be used to link failure to message
+ message_type: 'sms', // message must be sms (goal of the test)
+ model: 'mail.channel', // expected value to link message to channel
+ res_id: 31, // id of a random channel
+ }
+ );
+ this.data['mail.notification'].records.push(
+ // failure that is expected to be used in the test
+ {
+ mail_message_id: 11, // id of the related message
+ notification_status: 'exception', // necessary value to have a failure
+ notification_type: 'sms', // expected failure type for sms message
+ }
+ );
+ const bus = new Bus();
+ bus.on('do-action', null, payload => {
+ assert.step('do_action');
+ assert.strictEqual(
+ payload.action,
+ 'sms.sms_cancel_action',
+ "action should be the one to cancel sms"
+ );
+ assert.strictEqual(
+ payload.options.additional_context.default_model,
+ 'mail.channel',
+ "action should have the group model as default_model"
+ );
+ assert.strictEqual(
+ payload.options.additional_context.unread_counter,
+ 1,
+ "action should have the group notification length as unread_counter"
+ );
+ });
+
+ await this.start({ env: { bus } });
+ await this.createNotificationListComponent();
+
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationGroup_markAsRead',
+ "should have 1 mark as read button"
+ );
+
+ document.querySelector('.o_NotificationGroup_markAsRead').click();
+ assert.verifySteps(
+ ['do_action'],
+ "should do an action to display the cancel sms dialog"
+ );
+});
+
+QUnit.test('notifications grouped by notification_type', async function (assert) {
+ assert.expect(11);
+
+ this.data['mail.message'].records.push(
+ // first message that is expected to have a failure
+ {
+ id: 11, // random unique id, will be used to link failure to message
+ message_type: 'email', // different type from second message
+ model: 'res.partner', // same model as second message (and not `mail.channel`)
+ res_id: 31, // same res_id as second message
+ res_model_name: "Partner", // random related model name
+ },
+ // second message that is expected to have a failure
+ {
+ id: 12, // random unique id, will be used to link failure to message
+ message_type: 'sms', // different type from first message
+ model: 'res.partner', // same model as first message (and not `mail.channel`)
+ res_id: 31, // same res_id as first message
+ res_model_name: "Partner", // same related model name for consistency
+ }
+ );
+ this.data['mail.notification'].records.push(
+ // first failure that is expected to be used in the test
+ {
+ mail_message_id: 11, // id of the related first message
+ notification_status: 'exception', // necessary value to have a failure
+ notification_type: 'email', // different type from second failure
+ },
+ // second failure that is expected to be used in the test
+ {
+ mail_message_id: 12, // id of the related second message
+ notification_status: 'exception', // necessary value to have a failure
+ notification_type: 'sms', // different type from first failure
+ }
+ );
+ await this.start();
+ await this.createNotificationListComponent();
+
+ assert.containsN(
+ document.body,
+ '.o_NotificationGroup',
+ 2,
+ "should have 2 notifications group"
+ );
+ const groups = document.querySelectorAll('.o_NotificationGroup');
+ assert.containsOnce(
+ groups[0],
+ '.o_NotificationGroup_name',
+ "should have 1 group name in first group"
+ );
+ assert.strictEqual(
+ groups[0].querySelector('.o_NotificationGroup_name').textContent,
+ "Partner",
+ "should have model name as group name"
+ );
+ assert.containsOnce(
+ groups[0],
+ '.o_NotificationGroup_counter',
+ "should have 1 group counter in first group"
+ );
+ assert.strictEqual(
+ groups[0].querySelector('.o_NotificationGroup_counter').textContent.trim(),
+ "(1)",
+ "should have 1 notification in first group"
+ );
+ assert.strictEqual(
+ groups[0].querySelector('.o_NotificationGroup_inlineText').textContent.trim(),
+ "An error occurred when sending an email.",
+ "should have the group text corresponding to email"
+ );
+ assert.containsOnce(
+ groups[1],
+ '.o_NotificationGroup_name',
+ "should have 1 group name in second group"
+ );
+ assert.strictEqual(
+ groups[1].querySelector('.o_NotificationGroup_name').textContent,
+ "Partner",
+ "should have second model name as group name"
+ );
+ assert.containsOnce(
+ groups[1],
+ '.o_NotificationGroup_counter',
+ "should have 1 group counter in second group"
+ );
+ assert.strictEqual(
+ groups[1].querySelector('.o_NotificationGroup_counter').textContent.trim(),
+ "(1)",
+ "should have 1 notification in second group"
+ );
+ assert.strictEqual(
+ groups[1].querySelector('.o_NotificationGroup_inlineText').textContent.trim(),
+ "An error occurred when sending an SMS.",
+ "should have the group text corresponding to sms"
+ );
+});
+
+QUnit.test('grouped notifications by document model', async function (assert) {
+ // If all failures linked to a document model refers to different documents,
+ // a single notification should group all failures that are linked to this
+ // document model.
+ assert.expect(12);
+
+ this.data['mail.message'].records.push(
+ // first message that is expected to have a failure
+ {
+ id: 11, // random unique id, will be used to link failure to message
+ message_type: 'sms', // message must be sms (goal of the test)
+ model: 'res.partner', // same model as second message (and not `mail.channel`)
+ res_id: 31, // different res_id from second message
+ res_model_name: "Partner", // random related model name
+ },
+ // second message that is expected to have a failure
+ {
+ id: 12, // random unique id, will be used to link failure to message
+ message_type: 'sms', // message must be sms (goal of the test)
+ model: 'res.partner', // same model as first message (and not `mail.channel`)
+ res_id: 32, // different res_id from first message
+ res_model_name: "Partner", // same related model name for consistency
+ }
+ );
+ this.data['mail.notification'].records.push(
+ // first failure that is expected to be used in the test
+ {
+ mail_message_id: 11, // id of the related first message
+ notification_status: 'exception', // necessary value to have a failure
+ notification_type: 'sms', // expected failure type for sms message
+ },
+ // second failure that is expected to be used in the test
+ {
+ mail_message_id: 12, // id of the related second message
+ notification_status: 'exception', // necessary value to have a failure
+ notification_type: 'sms', // expected failure type for sms message
+ }
+ );
+ const bus = new Bus();
+ bus.on('do-action', null, payload => {
+ assert.step('do_action');
+ assert.strictEqual(
+ payload.action.name,
+ "SMS Failures",
+ "action should have 'SMS Failures' as name",
+ );
+ assert.strictEqual(
+ payload.action.type,
+ 'ir.actions.act_window',
+ "action should have the type act_window"
+ );
+ assert.strictEqual(
+ payload.action.view_mode,
+ 'kanban,list,form',
+ "action should have 'kanban,list,form' as view_mode"
+ );
+ assert.strictEqual(
+ JSON.stringify(payload.action.views),
+ JSON.stringify([[false, 'kanban'], [false, 'list'], [false, 'form']]),
+ "action should have correct views"
+ );
+ assert.strictEqual(
+ payload.action.target,
+ 'current',
+ "action should have 'current' as target"
+ );
+ assert.strictEqual(
+ payload.action.res_model,
+ 'res.partner',
+ "action should have the group model as res_model"
+ );
+ assert.strictEqual(
+ JSON.stringify(payload.action.domain),
+ JSON.stringify([['message_has_sms_error', '=', true]]),
+ "action should have 'message_has_sms_error' as domain"
+ );
+ });
+
+ await this.start({ env: { bus } });
+ await this.createNotificationListComponent();
+
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationGroup',
+ "should have 1 notification group"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_NotificationGroup_counter',
+ "should have 1 group counter"
+ );
+ assert.strictEqual(
+ document.querySelector('.o_NotificationGroup_counter').textContent.trim(),
+ "(2)",
+ "should have 2 notifications in the group"
+ );
+
+ document.querySelector('.o_NotificationGroup').click();
+ assert.verifySteps(
+ ['do_action'],
+ "should do an action to display the related records"
+ );
+});
+
+});
+});
+});
+
+});