diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/sms/static/src/components | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/sms/static/src/components')
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" + ); +}); + +}); +}); +}); + +}); |
