[ADD] im_support: test suite

This revs. add a new test suite for the im_support module. Defining
a new suite was necessary as the im_support JS feature needs
specific keys to be defined in the session, otherwise its files are
simply skipped.
This commit is contained in:
Aaron Bohy
2018-06-21 13:55:10 +02:00
parent ffe9bb501b
commit b188d1fc1f
9 changed files with 508 additions and 0 deletions
+2
View File
@@ -1,2 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import main
+12
View File
@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import http
from odoo.http import request
class ImSupport(http.Controller):
@http.route('/im_support/tests', type='http', auth="user")
def test_suite(self, mod=None, **kwargs):
return request.render('im_support.support_qunit_suite')
@@ -0,0 +1,81 @@
odoo.define('im_support.test_utils', function (require) {
"use strict";
var supportSession = require('im_support.SupportSession');
var testUtils = require('web.test_utils');
/**
* Extended version of addMockEnvironment that mocks RPCs done to the Support
* server (CORS), and enables a longpolling to the Support server, optionally.
*
* @param {Widget} widget
* @param {Object} params
* @param {function} [params.mockSupportRPC]
* @param {boolean} [params.enableSupportPoll=false]
*/
function addMockSupportEnvironment(widget, params) {
// mock CORS RPCs
var originalRPC = supportSession.rpc;
var defaultMockSupportRPC = function (route, args) {
if (route === '/odoo_im_support/get_support_channel') {
return $.when({
available: true,
channel_type: 'livechat',
public: 'private',
uuid: args.channel_uuid,
});
}
if (route === '/odoo_im_support/fetch_messages') { // fetching history
return $.when([]);
}
if (route === '/odoo_im_support/chat_post') {
return $.when();
}
if (route === '/longpolling/support_poll') {
return $.Deferred();
}
};
supportSession.rpc = function (route, args) {
var result;
if (params.mockSupportRPC) {
var _super = this._super;
this._super = defaultMockSupportRPC.bind(this, route, args);
result = params.mockSupportRPC.apply(this, arguments);
this._super = _super;
} else {
result = defaultMockSupportRPC.apply(this, arguments);
}
return result;
};
testUtils.addMockEnvironment(widget, params);
var widgetDestroy = widget.destroy;
widget.destroy = function () {
supportSession.rpc = originalRPC;
widgetDestroy.call(this);
};
// intercepts the getItem call to localStorage service for key
// 'im_support.poll_timeout', to simulate a pending longpolling connection to
// the Support server, such that the initSupport initiates a poll connection
if (params.enableSupportPoll) {
testUtils.intercept(widget, 'call_service', function (ev) {
if (ev.data.service === 'local_storage') {
if (ev.data.method === 'getItem' && ev.data.args[0] === 'im_support.poll_timeout') {
ev.data.callback(Date.now() + (60 * 1000));
// hack to prevent the default mock to handle the request and erase the above value
ev.data.callback = function () {};
}
}
}, true);
// manually call initSupport (which is supposed to be called at webclient startup)
widget.call('chat_manager', 'initSupport');
}
}
return {
addMockSupportEnvironment: addMockSupportEnvironment,
};
});
@@ -0,0 +1,45 @@
odoo.define('im_support.systray_no_support_tests', function (require) {
"use strict";
/**
* The purpose of these tests is to ensure that im_support doesn't have an impact
* on the webclient when the support is not available.
*/
var ChatManager = require('mail.ChatManager');
var systray = require('mail.systray');
var mailTestUtils = require('mail.testUtils');
var testUtils = require('web.test_utils');
var createBusService = mailTestUtils.createBusService;
QUnit.module('im_support', {}, function () {
QUnit.module('systray', {
beforeEach: function () {
this.services = [ChatManager, createBusService()];
},
});
QUnit.test('messaging menu does not display the Support channel if not available', function (assert) {
// the Support channel should only be displayed if a support_token and a support_origin are
// specified in the session, which is not the case for this test
assert.expect(1);
var messagingMenu = new systray.MessagingMenu();
testUtils.addMockEnvironment(messagingMenu, {
services: this.services,
});
messagingMenu.appendTo($('#qunit-fixture'));
messagingMenu.$('.dropdown-toggle').click();
assert.strictEqual(messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').length,
0, "should not display the Support channel");
messagingMenu.destroy();
});
});
});
@@ -0,0 +1,320 @@
odoo.define('im_support.systray_tests', function (require) {
"use strict";
var supportBus = require('im_support.SupportBus');
var imSupportTestUtils = require('im_support.test_utils');
var ChatManager = require('mail.ChatManager');
var ChatWindowManager = require('mail.ChatWindowManager');
var systray = require('mail.systray');
var mailTestUtils = require('mail.testUtils');
var testUtils = require('web.test_utils');
var addMockSupportEnvironment = imSupportTestUtils.addMockSupportEnvironment;
var createBusService = mailTestUtils.createBusService;
QUnit.module('im_support', {}, function () {
QUnit.module('systray', {
beforeEach: function () {
this.services = [ChatManager, ChatWindowManager, createBusService()];
this.supportParams = {
db_uuid: 'some_uuid',
support_token: 'ABCDEFGHIJ',
support_origin: 'something.com',
};
},
});
QUnit.test('messaging menu displays the Support channel', function (assert) {
assert.expect(1);
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
services: this.services,
session: this.supportParams,
});
messagingMenu.appendTo($('#qunit-fixture'));
messagingMenu.$('.dropdown-toggle').click();
assert.strictEqual(messagingMenu.$('.o_mail_navbar_dropdown_bottom .o_mail_channel_preview[data-channel_id=SupportChannel]').length,
1, "should display the Support channel");
messagingMenu.destroy();
});
QUnit.test('clicking on Support channel: channel not available', function (assert) {
assert.expect(9);
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
},
mockSupportRPC: function (route) {
assert.step('cors: ' + route);
if (route === '/odoo_im_support/get_support_channel') {
return this._super.apply(this, arguments).then(function (supportChannel) {
supportChannel.available = false;
return supportChannel;
});
}
return this._super.apply(this, arguments);
},
services: this.services,
session: this.supportParams,
});
messagingMenu.appendTo($('#qunit-fixture'));
messagingMenu.$('.dropdown-toggle').click();
assert.strictEqual(messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').length,
1, "should display the Support channel");
messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').click();
assert.strictEqual($('.o_chat_window').length, 1,
"should have open a chat window");
assert.strictEqual($('.o_chat_window .o_chat_title').text().trim(), 'Support (offline)',
"should display the offline status in the header");
assert.strictEqual($('.o_chat_window .o_composer_input').length, 0,
"should have no composer");
assert.verifySteps([
'/mail/init_messaging',
'message_fetch',
'cors: /odoo_im_support/get_support_channel',
'cors: /odoo_im_support/fetch_messages',
]);
messagingMenu.destroy();
});
QUnit.test('clicking on Support channel: channel available', function (assert) {
assert.expect(9);
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
},
mockSupportRPC: function (route) {
if (route.split('/')[1] === 'odoo_im_support') {
assert.step('cors: ' + route);
}
return this._super.apply(this, arguments);
},
services: this.services,
session: this.supportParams,
});
messagingMenu.appendTo($('#qunit-fixture'));
messagingMenu.$('.dropdown-toggle').click();
assert.strictEqual(messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').length,
1, "should display the Support channel");
messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').click();
assert.strictEqual($('.o_chat_window').length, 1,
"should have open a chat window");
assert.strictEqual($('.o_chat_window .o_chat_title').text().trim(), 'Support',
"should display the correct channel title");
assert.strictEqual($('.o_chat_window .o_composer_input').length, 1,
"should have a composer");
assert.verifySteps([
'/mail/init_messaging',
'message_fetch',
'cors: /odoo_im_support/get_support_channel',
'cors: /odoo_im_support/fetch_messages',
]);
messagingMenu.destroy();
});
QUnit.test('post messages in Support channel', function (assert) {
assert.expect(8);
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
},
mockSupportRPC: function (route) {
if (route.split('/')[1] === 'odoo_im_support') {
assert.step('cors: ' + route);
}
return this._super.apply(this, arguments);
},
services: this.services,
session: this.supportParams,
});
messagingMenu.appendTo($('#qunit-fixture'));
messagingMenu.$('.dropdown-toggle').click();
assert.strictEqual(messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').length,
1, "should display the Support channel");
messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').click();
assert.strictEqual($('.o_chat_window .o_composer_input').length, 1,
"should have a composer");
$('.o_chat_window .o_composer_input .o_input')
.val('some message')
.trigger($.Event('keydown', {which: $.ui.keyCode.ENTER}));
assert.verifySteps([
'/mail/init_messaging',
'message_fetch',
'cors: /odoo_im_support/get_support_channel',
'cors: /odoo_im_support/fetch_messages',
'cors: /odoo_im_support/chat_post',
]);
messagingMenu.destroy();
});
QUnit.test('fold Support channel', function (assert) {
assert.expect(11);
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
},
mockSupportRPC: function (route) {
if (route.split('/')[1] === 'odoo_im_support') {
assert.step('cors: ' + route);
}
return this._super.apply(this, arguments);
},
services: this.services,
session: this.supportParams,
});
testUtils.intercept(messagingMenu, 'call_service', function (ev) {
if (ev.data.service === 'local_storage') {
assert.step('LocalStorage: ' + ev.data.method + ' ' + ev.data.args);
}
}, true);
messagingMenu.appendTo($('#qunit-fixture'));
messagingMenu.$('.dropdown-toggle').click();
assert.strictEqual(messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').length,
1, "should display the Support channel");
messagingMenu.$('.o_mail_channel_preview[data-channel_id=SupportChannel]').click();
assert.strictEqual($('.o_chat_window').length, 1,
"should have open a chat window");
// fold, re-open and close channel
$('.o_chat_window .o_chat_title').click();
$('.o_chat_window .o_chat_title').click();
$('.o_chat_window .o_chat_window_close').click();
assert.verifySteps([
'/mail/init_messaging',
'message_fetch',
'cors: /odoo_im_support/get_support_channel',
'LocalStorage: setItem im_support.channel_state,open',
'cors: /odoo_im_support/fetch_messages',
'LocalStorage: setItem im_support.channel_state,folded',
'LocalStorage: setItem im_support.channel_state,open',
'LocalStorage: setItem im_support.channel_state,closed',
]);
messagingMenu.destroy();
});
QUnit.test('restore Support channel if necessary', function (assert) {
assert.expect(5);
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
enableSupportPoll: true,
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
},
mockSupportRPC: function (route) {
if (route.split('/')[1] === 'odoo_im_support') {
assert.step('cors: ' + route);
}
return this._super.apply(this, arguments);
},
services: this.services,
session: this.supportParams,
});
messagingMenu.appendTo($('#qunit-fixture'));
assert.strictEqual($('.o_chat_window').length, 1,
"should have open a chat window");
assert.verifySteps([
'/mail/init_messaging',
'cors: /odoo_im_support/get_support_channel',
'cors: /odoo_im_support/fetch_messages',
]);
messagingMenu.destroy();
});
QUnit.test('receive messages in the Support channel', function (assert) {
assert.expect(10);
var supportChannelID;
var messagingMenu = new systray.MessagingMenu();
addMockSupportEnvironment(messagingMenu, {
enableSupportPoll: true,
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
},
mockSupportRPC: function (route) {
if (route.split('/')[1] === 'odoo_im_support') {
assert.step('cors: ' + route);
}
return this._super.apply(this, arguments);
},
services: this.services,
session: this.supportParams,
});
messagingMenu.appendTo($('#qunit-fixture'));
assert.strictEqual($('.o_chat_window').length, 1,
"should have open a chat window");
assert.strictEqual($('.o_chat_window .o_thread_message').length, 0,
"there should be no message in the thread");
// simulate an incoming message on the supportBus
var data = {
author_id: [42, 'An operator'],
body: 'A message',
channel_ids: [supportChannelID],
};
var notification = [[false, 'mail.channel'], data];
supportBus.trigger('notification', [notification]);
assert.strictEqual($('.o_chat_window .o_thread_message').length, 1,
"there should be a new message in the thread");
assert.strictEqual($('.o_chat_window .o_thread_message .o_thread_author ').text().trim(),
'An operator', "should correctly display the author");
assert.strictEqual($('.o_chat_window .o_thread_message .o_thread_message_avatar').attr('src'),
'/mail/static/src/img/odoo_o.png', "should have correct avatar");
assert.strictEqual($('.o_chat_window .o_thread_message .o_thread_message_content ').text().trim(),
'A message', "message is correct");
assert.verifySteps([
'/mail/init_messaging',
'cors: /odoo_im_support/get_support_channel',
'cors: /odoo_im_support/fetch_messages',
]);
messagingMenu.destroy();
});
});
});
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_js
+11
View File
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
@odoo.tests.tagged('post_install', '-at_install')
class IMSupportSuite(odoo.tests.HttpCase):
def test_im_support_js(self):
self.phantom_js('/im_support/tests?mod=web&failfast', "", "", login='admin', timeout=180)
+29
View File
@@ -12,5 +12,34 @@
<script type="text/javascript" src="/im_support/static/src/js/systray.js"></script>
</xpath>
</template>
<template id="qunit_suite" name="im_support_tests" inherit_id="web.qunit_suite">
<xpath expr="//t[@t-set='head']" position="inside">
<script type="text/javascript" src="/im_support/static/tests/systray_no_support_tests.js"></script>
</xpath>
</template>
<template id="im_support.support_qunit_suite">
<t t-call="web.layout">
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
<t t-set="title">IM Support Tests</t>
<t t-set="head">
<script type="text/javascript">
odoo.session_info = {
support_token: 'ABCDEFGHIJ',
support_origin: 'https://something.com'
};
</script>
<t t-call="web.js_tests_assets"/>
<script type="text/javascript" src="/im_support/static/tests/helpers/test_utils.js"></script>
<script type="text/javascript" src="/im_support/static/tests/systray_tests.js"></script>
</t>
<div id="qunit"/>
<div id="qunit-fixture"/>
</t>
</template>
</data>
</openerp>