diff options
| author | Sébastien Theys <seb@odoo.com> | 2020-06-15 18:12:21 +0000 |
|---|---|---|
| committer | Sébastien Theys <seb@odoo.com> | 2020-06-15 18:12:21 +0000 |
| commit | 3fea5b2136627c1d7e83b2a5e111952fe3eb10a1 (patch) | |
| tree | 5eefad07972a87ce4689b83260f981bc87aadad4 /addons/snailmail/static/src/components/message/message_tests.js | |
| parent | 0a82848606151ef60eb6523e9c4c161171f214e7 (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/snailmail/static/src/components/message/message_tests.js')
| -rw-r--r-- | addons/snailmail/static/src/components/message/message_tests.js | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/addons/snailmail/static/src/components/message/message_tests.js b/addons/snailmail/static/src/components/message/message_tests.js new file mode 100644 index 00000000000..10f917b2bbe --- /dev/null +++ b/addons/snailmail/static/src/components/message/message_tests.js @@ -0,0 +1,624 @@ +odoo.define('snailmail/static/src/components/message/message_tests.js', function (require) { +'use strict'; + +const components = { + Message: require('mail/static/src/components/message/message.js'), +}; +const { + afterEach: utilsAfterEach, + afterNextRender, + beforeEach: utilsBeforeEach, + start: utilsStart, +} = require('mail/static/src/utils/test_utils.js'); + +const Bus = require('web.Bus'); + +QUnit.module('snailmail', {}, function () { +QUnit.module('components', {}, function () { +QUnit.module('message', {}, function () { +QUnit.module('message_tests.js', { + beforeEach() { + utilsBeforeEach(this); + + this.createMessageComponent = async message => { + const MessageComponent = components.Message; + MessageComponent.env = this.env; + this.component = new MessageComponent(null, { + messageLocalId: message.localId, + }); + delete MessageComponent.env; + await 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) { + // The component must be destroyed before the widget, because the + // widget might destroy the models before destroying the component, + // and the Message component is relying on messaging. + this.component.destroy(); + } + if (this.widget) { + this.widget.destroy(); + } + this.env = undefined; + }, +}); + +QUnit.test('Sent', async function (assert) { + assert.expect(8); + + await this.start(); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + id: 11, + notification_status: 'sent', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.containsOnce( + document.body, + '.o_SnailmailNotificationPopover', + "notification popover should be open" + ); + assert.containsOnce( + document.body, + '.o_SnailmailNotificationPopover_icon', + "popover should have one icon" + ); + assert.hasClass( + document.querySelector('.o_SnailmailNotificationPopover_icon'), + 'fa-check', + "popover should have the sent icon" + ); + assert.strictEqual( + document.querySelector('.o_SnailmailNotificationPopover').textContent.trim(), + "Sent", + "popover should have the sent text" + ); +}); + +QUnit.test('Canceled', async function (assert) { + assert.expect(8); + + await this.start(); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + id: 11, + notification_status: 'canceled', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.containsOnce( + document.body, + '.o_SnailmailNotificationPopover', + "notification popover should be open" + ); + assert.containsOnce( + document.body, + '.o_SnailmailNotificationPopover_icon', + "popover should have one icon" + ); + assert.hasClass( + document.querySelector('.o_SnailmailNotificationPopover_icon'), + 'fa-trash-o', + "popover should have the canceled icon" + ); + assert.strictEqual( + document.querySelector('.o_SnailmailNotificationPopover').textContent.trim(), + "Canceled", + "popover should have the canceled text" + ); +}); + +QUnit.test('Pending', async function (assert) { + assert.expect(8); + + await this.start(); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + id: 11, + notification_status: 'ready', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.containsOnce( + document.body, + '.o_SnailmailNotificationPopover', + "notification popover should be open" + ); + assert.containsOnce( + document.body, + '.o_SnailmailNotificationPopover_icon', + "popover should have one icon" + ); + assert.hasClass( + document.querySelector('.o_SnailmailNotificationPopover_icon'), + 'fa-clock-o', + "popover should have the pending icon" + ); + assert.strictEqual( + document.querySelector('.o_SnailmailNotificationPopover').textContent.trim(), + "Awaiting Dispatch", + "popover should have the pending text" + ); +}); + +QUnit.test('No Price Available', async function (assert) { + assert.expect(10); + + await this.start({ + async mockRPC(route, args) { + if (args.method === 'cancel_letter' && args.model === 'mail.message' && args.args[0][0] === 10) { + assert.step(args.method); + return; + } + return this._super(...arguments); + }, + }); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + failure_type: 'sn_price', + id: 11, + notification_status: 'exception', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog', + "error dialog should be open" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_contentPrice', + "error dialog should have the 'no price' content" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_cancelLetterButton', + "dialog should have a 'Cancel letter' button" + ); + + await afterNextRender(() => { + document.querySelector('.o_SnailmailErrorDialog_cancelLetterButton').click(); + }); + assert.containsNone( + document.body, + '.o_SnailmailErrorDialog', + "dialog should be closed after click on 'Cancel letter'" + ); + assert.verifySteps( + ['cancel_letter'], + "should have made a RPC call to 'cancel_letter'" + ); +}); + +QUnit.test('Credit Error', async function (assert) { + assert.expect(11); + + await this.start({ + async mockRPC(route, args) { + if (args.method === 'send_letter' && args.model === 'mail.message' && args.args[0][0] === 10) { + assert.step(args.method); + return; + } + if (args.method === 'get_credits_url') { + return 'credits_url'; + } + return this._super(...arguments); + }, + }); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + failure_type: 'sn_credit', + id: 11, + notification_status: 'exception', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog', + "error dialog should be open" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_contentCredit', + "error dialog should have the 'credit' content" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_resendLetterButton', + "dialog should have a 'Re-send letter' button" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_cancelLetterButton', + "dialog should have a 'Cancel letter' button" + ); + + await afterNextRender(() => { + document.querySelector('.o_SnailmailErrorDialog_resendLetterButton').click(); + }); + assert.containsNone( + document.body, + '.o_SnailmailErrorDialog', + "dialog should be closed after click on 'Re-send letter'" + ); + assert.verifySteps( + ['send_letter'], + "should have made a RPC call to 'send_letter'" + ); +}); + +QUnit.test('Trial Error', async function (assert) { + assert.expect(11); + + await this.start({ + async mockRPC(route, args) { + if (args.method === 'send_letter' && args.model === 'mail.message' && args.args[0][0] === 10) { + assert.step(args.method); + return; + } + if (args.method === 'get_credits_url') { + return 'credits_url_trial'; + } + return this._super(...arguments); + }, + }); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + failure_type: 'sn_trial', + id: 11, + notification_status: 'exception', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog', + "error dialog should be open" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_contentTrial', + "error dialog should have the 'trial' content" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_resendLetterButton', + "dialog should have a 'Re-send letter' button" + ); + assert.containsOnce( + document.body, + '.o_SnailmailErrorDialog_cancelLetterButton', + "dialog should have a 'Cancel letter' button" + ); + + await afterNextRender(() => { + document.querySelector('.o_SnailmailErrorDialog_resendLetterButton').click(); + }); + assert.containsNone( + document.body, + '.o_SnailmailErrorDialog', + "dialog should be closed after click on 'Re-send letter'" + ); + assert.verifySteps( + ['send_letter'], + "should have made a RPC call to 'send_letter'" + ); +}); + +QUnit.test('Format Error', async function (assert) { + assert.expect(8); + + const bus = new Bus(); + bus.on('do-action', null, payload => { + assert.step('do_action'); + assert.strictEqual( + payload.action, + 'snailmail.snailmail_letter_format_error_action', + "action should be the one for format error" + ); + assert.strictEqual( + payload.options.additional_context.message_id, + 10, + "action should have correct message id" + ); + }); + + await this.start({ env: { bus } }); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + failure_type: 'sn_format', + id: 11, + notification_status: 'exception', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.verifySteps( + ['do_action'], + "should do an action to display the format error dialog" + ); +}); + +QUnit.test('Missing Required Fields', async function (assert) { + assert.expect(9); + + const bus = new Bus(); + bus.on('do-action', null, payload => { + assert.step('do_action'); + assert.strictEqual( + payload.action, + 'snailmail.snailmail_letter_missing_required_fields_action', + "action should be the one for missing fields" + ); + assert.strictEqual( + payload.options.additional_context.letter_id, + 22, // should be the same as the id returned by search + "action should have correct letter id" + ); + }); + + await this.start({ + env: { bus }, + async mockRPC(route, args) { + if (args.model === 'snailmail.letter' && args.method === 'search') { + assert.step('search'); + return [22]; // should be the same as the id given to the action + } + return this._super(...arguments); + }, + }); + const message = this.env.models['mail.message'].create({ + id: 10, + message_type: 'snailmail', + notifications: [['insert', { + failure_type: 'sn_fields', + id: 11, + notification_status: 'exception', + notification_type: 'snail', + }]], + }); + await this.createMessageComponent(message); + + assert.containsOnce( + document.body, + '.o_Message', + "should display a message component" + ); + assert.containsOnce( + document.body, + '.o_Message_notificationIconContainer', + "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-paper-plane', + "icon should represent snailmail" + ); + + await afterNextRender(() => { + document.querySelector('.o_Message_notificationIconContainer').click(); + }); + assert.verifySteps( + ['search', 'do_action'], + "the id of the letter related to the message should be returned by a search and an action should be done to display the missing fields dialog" + ); +}); + +}); +}); +}); + +}); |
