[MERGE] web,*: properly set up Owl env in the frontend
This PR extracts the common basis of the env to use both in the frontend and the backend. The public env now contains most of the features that were previously (only) in the webclient env. Moreover, the PublicRoot no longer uses the ServiceProviderMixin, such that services are only deployed once, in the (public) env. AbstractService now takes the env as argument in the constructor, instead of the parent. Finally, test helpers (and tests) are adapted accordingly. Task 2274713 closes odoo/odoo#52097 Related: odoo/enterprise#10989 Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
This commit is contained in:
@@ -4,6 +4,7 @@ odoo.define('bus.BusService', function (require) {
|
||||
var CrossTab = require('bus.CrossTab');
|
||||
var core = require('web.core');
|
||||
var ServicesMixin = require('web.ServicesMixin');
|
||||
const session = require('web.session');
|
||||
|
||||
var BusService = CrossTab.extend(ServicesMixin, {
|
||||
dependencies : ['local_storage'],
|
||||
@@ -11,6 +12,38 @@ var BusService = CrossTab.extend(ServicesMixin, {
|
||||
// properties
|
||||
_audio: null,
|
||||
|
||||
/**
|
||||
* As the BusService doesn't extend AbstractService, we have to replicate
|
||||
* here what is done in AbstractService
|
||||
*
|
||||
* @param {Object} env
|
||||
*/
|
||||
init: function (env) {
|
||||
this.env = env;
|
||||
this._super();
|
||||
},
|
||||
|
||||
/**
|
||||
* Replicate the behavior of AbstractService:
|
||||
*
|
||||
* Directly calls the requested service, instead of triggering a
|
||||
* 'call_service' event up, which wouldn't work as services have no parent.
|
||||
*
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
_trigger_up: function (ev) {
|
||||
if (ev.name === 'call_service') {
|
||||
const payload = ev.data;
|
||||
let args = payload.args || [];
|
||||
if (payload.service === 'ajax' && payload.method === 'rpc') {
|
||||
// ajax service uses an extra 'target' argument for rpc
|
||||
args = args.concat(ev.target);
|
||||
}
|
||||
const service = this.env.services[payload.service];
|
||||
const result = service[payload.method].apply(service, args);
|
||||
payload.callback(result);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This method is necessary in order for this Class to be used to instantiate services
|
||||
*
|
||||
@@ -77,7 +110,6 @@ var BusService = CrossTab.extend(ServicesMixin, {
|
||||
if (!this._audio) {
|
||||
this._audio = new Audio();
|
||||
var ext = this._audio.canPlayType("audio/ogg; codecs=vorbis") ? ".ogg" : ".mp3";
|
||||
var session = this.getSession();
|
||||
this._audio.src = session.url("/mail/static/src/audio/ting" + ext);
|
||||
}
|
||||
Promise.resolve(this._audio.play()).catch(_.noop);
|
||||
|
||||
@@ -27,7 +27,7 @@ QUnit.module('Bus', {
|
||||
var pollPromise = testUtils.makeTestPromise();
|
||||
|
||||
var parent = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parent, {
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: {},
|
||||
services: {
|
||||
bus_service: BusService,
|
||||
@@ -101,7 +101,7 @@ QUnit.module('Bus', {
|
||||
|
||||
var pollPromise = testUtils.makeTestPromise();
|
||||
var parent = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parent, {
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: {},
|
||||
services: {
|
||||
bus_service: BusService,
|
||||
@@ -142,7 +142,7 @@ QUnit.module('Bus', {
|
||||
var pollPromiseMaster = testUtils.makeTestPromise();
|
||||
|
||||
var parentMaster = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parentMaster, {
|
||||
await testUtils.mock.addMockEnvironment(parentMaster, {
|
||||
data: {},
|
||||
services: {
|
||||
bus_service: BusService,
|
||||
@@ -173,7 +173,7 @@ QUnit.module('Bus', {
|
||||
// slave
|
||||
await testUtils.nextTick();
|
||||
var parentSlave = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parentSlave, {
|
||||
await testUtils.mock.addMockEnvironment(parentSlave, {
|
||||
data: {},
|
||||
services: {
|
||||
bus_service: BusService,
|
||||
@@ -220,7 +220,7 @@ QUnit.module('Bus', {
|
||||
var pollPromiseMaster = testUtils.makeTestPromise();
|
||||
|
||||
var parentMaster = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parentMaster, {
|
||||
await testUtils.mock.addMockEnvironment(parentMaster, {
|
||||
data: {},
|
||||
services: {
|
||||
bus_service: BusService,
|
||||
@@ -252,7 +252,7 @@ QUnit.module('Bus', {
|
||||
await testUtils.nextTick();
|
||||
var parentSlave = new Widget();
|
||||
var pollPromiseSlave = testUtils.makeTestPromise();
|
||||
testUtils.mock.addMockEnvironment(parentSlave, {
|
||||
await testUtils.mock.addMockEnvironment(parentSlave, {
|
||||
data: {},
|
||||
services: {
|
||||
bus_service: BusService,
|
||||
|
||||
@@ -41,7 +41,7 @@ QUnit.test('activity menu widget:today meetings', async function (assert) {
|
||||
assert.expect(6);
|
||||
var self = this;
|
||||
var activityMenu = new ActivityMenu();
|
||||
testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
await testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
|
||||
@@ -59,7 +59,7 @@ QUnit.module('HR Attendance', {
|
||||
|
||||
var $target = $('#qunit-fixture');
|
||||
var clientAction = new MyAttendances(null, {});
|
||||
testUtils.mock.addMockEnvironment(clientAction, {
|
||||
await testUtils.mock.addMockEnvironment(clientAction, {
|
||||
data: this.data,
|
||||
session: {
|
||||
uid: 1,
|
||||
@@ -80,7 +80,7 @@ QUnit.module('HR Attendance', {
|
||||
var self = this;
|
||||
var rpcCount = 0;
|
||||
var clientAction = new KioskMode(null, {});
|
||||
testUtils.mock.addMockEnvironment(clientAction, {
|
||||
await testUtils.mock.addMockEnvironment(clientAction, {
|
||||
data: this.data,
|
||||
session: {
|
||||
uid: 1,
|
||||
@@ -124,7 +124,7 @@ QUnit.module('HR Attendance', {
|
||||
barcode: barcode,
|
||||
};
|
||||
var clientAction = new GreetingMessage(null, action);
|
||||
testUtils.mock.addMockEnvironment(clientAction, {
|
||||
await testUtils.mock.addMockEnvironment(clientAction, {
|
||||
data: self.data,
|
||||
session: {
|
||||
uid: 1,
|
||||
|
||||
@@ -45,7 +45,7 @@ QUnit.test('basic rendering', async function (assert) {
|
||||
livechat.setMessages(messages);
|
||||
|
||||
var chatWindow = new ChatWindow(parent, livechat);
|
||||
testUtils.mock.addMockEnvironment(parent, {});
|
||||
await testUtils.mock.addMockEnvironment(parent, {});
|
||||
await chatWindow.appendTo($('#qunit-fixture'));
|
||||
chatWindow.render();
|
||||
|
||||
@@ -95,7 +95,7 @@ QUnit.test('define several livechat colors', async function (assert) {
|
||||
headerBackgroundColor: 'yellow',
|
||||
titleColor: 'green',
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(parent, {});
|
||||
await testUtils.mock.addMockEnvironment(parent, {});
|
||||
await chatWindow.appendTo($('#qunit-fixture'));
|
||||
chatWindow.render();
|
||||
assert.strictEqual(
|
||||
|
||||
@@ -1004,7 +1004,7 @@ var MailManager = AbstractService.extend({
|
||||
_t("%d Messages"),
|
||||
this._outOfFocusUnreadMessageCounter
|
||||
);
|
||||
this.trigger_up('set_title_part', {
|
||||
this.env.bus.trigger('set_title_part', {
|
||||
part: '_chat',
|
||||
title: tabTitle
|
||||
});
|
||||
@@ -1048,12 +1048,14 @@ var MailManager = AbstractService.extend({
|
||||
* @param {string} viewID
|
||||
*/
|
||||
_redirectToDocument: function (resModel, resID, viewID) {
|
||||
this.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
view_mode: 'form',
|
||||
res_model: resModel,
|
||||
views: [[viewID || false, 'form']],
|
||||
res_id: resID,
|
||||
this.env.bus.trigger('do-action', {
|
||||
action: {
|
||||
type: 'ir.actions.act_window',
|
||||
view_mode: 'form',
|
||||
res_model: resModel,
|
||||
views: [[viewID || false, 'form']],
|
||||
res_id: resID,
|
||||
},
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -1345,7 +1347,7 @@ var MailManager = AbstractService.extend({
|
||||
*/
|
||||
_onWindowFocus: function () {
|
||||
this._resetOutOfFocusUnreadMessageCounter();
|
||||
this.trigger_up('set_title_part', { part: '_chat' });
|
||||
this.env.bus.trigger('set_title_part', { part: '_chat' });
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
odoo.define('mail.documentThreadWindowTests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const Bus = require('web.Bus');
|
||||
const LocalStorageService = require('web.LocalStorageService');
|
||||
var mailTestUtils = require('mail.testUtils');
|
||||
var MessagingMenu = require('mail.systray.MessagingMenu');
|
||||
|
||||
@@ -128,20 +130,23 @@ QUnit.test('open a document thread in a thread window', async function (assert)
|
||||
QUnit.test('expand a document thread window', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const bus = new Bus();
|
||||
bus.on('do-action', null, function (payload) {
|
||||
assert.deepEqual(payload.action, {
|
||||
res_id: 1,
|
||||
res_model: 'some.res.model',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'form']],
|
||||
}, "should open the document in form view");
|
||||
});
|
||||
|
||||
var messagingMenu = new MessagingMenu();
|
||||
await testUtils.mock.addMockEnvironment(messagingMenu, {
|
||||
services: this.services,
|
||||
data: this.data,
|
||||
session: this.session,
|
||||
intercepts: {
|
||||
do_action: function (ev) {
|
||||
assert.deepEqual(ev.data.action, {
|
||||
res_id: 1,
|
||||
res_model: 'some.res.model',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'form']],
|
||||
}, "should open the document in form view");
|
||||
},
|
||||
env: {
|
||||
bus
|
||||
},
|
||||
});
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
@@ -177,8 +182,18 @@ QUnit.test('post messages in a document thread window', async function (assert)
|
||||
res_id: 1,
|
||||
};
|
||||
var messagingMenu = new MessagingMenu();
|
||||
const MockedLocalStorageService = LocalStorageService.extend({
|
||||
setItem(key, value) {
|
||||
if (key === 'mail.document_threads_last_message') {
|
||||
assert.deepEqual(value.messageData, newMessage,
|
||||
"should write sent message in local storage, to share info with other tabs");
|
||||
}
|
||||
},
|
||||
});
|
||||
await testUtils.mock.addMockEnvironment(messagingMenu, {
|
||||
services: this.services,
|
||||
services: Object.assign(this.services, {
|
||||
local_storage: MockedLocalStorageService,
|
||||
}),
|
||||
data: this.data,
|
||||
session: this.session,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -198,13 +213,7 @@ QUnit.test('post messages in a document thread window', async function (assert)
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
testUtils.mock.intercept(messagingMenu, 'call_service', function (ev) {
|
||||
if (ev.data.service === 'local_storage' && ev.data.method === 'setItem' &&
|
||||
ev.data.args[0] === 'mail.document_threads_last_message') {
|
||||
assert.deepEqual(ev.data.args[1].messageData, newMessage,
|
||||
"should write sent message in local storage, to share info with other tabs");
|
||||
}
|
||||
}, true);
|
||||
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// toggle the messaging menu and open the documentThread
|
||||
@@ -229,24 +238,25 @@ QUnit.test('post messages in a document thread window', async function (assert)
|
||||
QUnit.test('open, fold, unfold and close a document thread window', async function (assert) {
|
||||
assert.expect(20);
|
||||
var messagingMenu = new MessagingMenu();
|
||||
await testUtils.mock.addMockEnvironment(messagingMenu, {
|
||||
services: this.services,
|
||||
data: this.data,
|
||||
session: this.session,
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
testUtils.mock.intercept(messagingMenu, 'call_service', function (ev) {
|
||||
if (ev.data.service === 'local_storage' && ev.data.method === 'setItem') {
|
||||
const key = ev.data.args[0];
|
||||
const MockedLocalStorageService = LocalStorageService.extend({
|
||||
setItem(key, value) {
|
||||
if (key === 'mail.document_threads_state/some.res.model_1') {
|
||||
const state = ev.data.args[1].state;
|
||||
const state = value.state;
|
||||
assert.ok(state);
|
||||
assert.ok(state.name);
|
||||
assert.ok(state.windowState);
|
||||
assert.step(`${key}: { name: "${state.name}", windowState: '${state.windowState}' }`);
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
await testUtils.mock.addMockEnvironment(messagingMenu, {
|
||||
services: Object.assign(this.services, {
|
||||
local_storage: MockedLocalStorageService,
|
||||
}),
|
||||
data: this.data,
|
||||
session: this.session,
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
await messagingMenu.appendTo($('#qunit-fixture'));
|
||||
|
||||
// toggle the messaging menu and open the documentThread
|
||||
|
||||
@@ -14,7 +14,7 @@ var Widget = require('web.Widget');
|
||||
* @param {boolean} [params.debug]
|
||||
* @returns {DocumentViewer}
|
||||
*/
|
||||
var createViewer = function (params) {
|
||||
var createViewer = async function (params) {
|
||||
var parent = new Widget();
|
||||
var viewer = new DocumentViewer(parent, params.attachments, params.attachmentID);
|
||||
|
||||
@@ -32,7 +32,7 @@ var createViewer = function (params) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
testUtils.mock.addMockEnvironment(parent, {
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
mockRPC: function () {
|
||||
if (params.mockRPC) {
|
||||
var _super = this._super;
|
||||
|
||||
@@ -17,9 +17,9 @@ QUnit.module('Status manager', {
|
||||
this.timeoutMock = mailTestUtils.patchMailTimeouts();
|
||||
},
|
||||
});
|
||||
QUnit.test('simple set im_status', function (assert) {
|
||||
QUnit.test('simple set im_status', async function (assert) {
|
||||
assert.expect(1);
|
||||
var parent = testUtils.createParent({
|
||||
var parent = await testUtils.createParent({
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/mail/init_messaging') {
|
||||
@@ -41,7 +41,7 @@ QUnit.test('simple set im_status', function (assert) {
|
||||
QUnit.test('multi get_im_status', async function (assert) {
|
||||
assert.expect(8);
|
||||
var readCount = 0;
|
||||
var parent = testUtils.createParent({
|
||||
var parent = await testUtils.createParent({
|
||||
//data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -86,7 +86,7 @@ QUnit.test('multi get_im_status', async function (assert) {
|
||||
QUnit.test('update loop', async function (assert) {
|
||||
assert.expect(10);
|
||||
var readCount = 0;
|
||||
var parent = testUtils.createParent({
|
||||
var parent = await testUtils.createParent({
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/mail/init_messaging') {
|
||||
@@ -162,7 +162,7 @@ QUnit.test('update status', async function (assert) {
|
||||
}
|
||||
});
|
||||
var statusWidget = new StatusWidget();
|
||||
testUtils.mock.addMockEnvironment(statusWidget, {
|
||||
await testUtils.mock.addMockEnvironment(statusWidget, {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/mail/init_messaging') {
|
||||
|
||||
@@ -31,7 +31,7 @@ QUnit.module('mail', {
|
||||
QUnit.module('model', {}, function () {
|
||||
QUnit.module('CC Throttle Function');
|
||||
|
||||
QUnit.test('cancel()', function (assert) {
|
||||
QUnit.test('cancel()', async function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(3);
|
||||
|
||||
@@ -39,7 +39,7 @@ QUnit.test('cancel()', function (assert) {
|
||||
var def = testUtils.makeTestPromise();
|
||||
var step = 1;
|
||||
|
||||
var widget = testUtils.createParent({
|
||||
var widget = await testUtils.createParent({
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === '__rpc__') {
|
||||
assert.step(args.method + args.args[0]);
|
||||
@@ -87,7 +87,7 @@ QUnit.test('cancel()', function (assert) {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('clear()', function (assert) {
|
||||
QUnit.test('clear()', async function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(5);
|
||||
|
||||
@@ -96,7 +96,7 @@ QUnit.test('clear()', function (assert) {
|
||||
var def2 = testUtils.makeTestPromise();
|
||||
var step = 1;
|
||||
|
||||
var widget = testUtils.createParent({
|
||||
var widget = await testUtils.createParent({
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === '__rpc__') {
|
||||
assert.step(args.method + args.args[0]);
|
||||
|
||||
@@ -83,7 +83,7 @@ QUnit.test('activity menu widget: menu with no records', async function (assert)
|
||||
assert.expect(1);
|
||||
|
||||
var activityMenu = new ActivityMenu();
|
||||
testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
await testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
@@ -102,7 +102,7 @@ QUnit.test('activity menu widget: activity menu with 3 records', async function
|
||||
assert.expect(10);
|
||||
var self = this;
|
||||
var activityMenu = new ActivityMenu();
|
||||
testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
await testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
@@ -163,7 +163,7 @@ QUnit.test('activity menu widget: activity view icon', async function (assert) {
|
||||
assert.expect(12);
|
||||
var self = this;
|
||||
var activityMenu = new ActivityMenu();
|
||||
testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
await testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
services: this.services,
|
||||
session: this.session,
|
||||
mockRPC: function (route, args) {
|
||||
|
||||
@@ -56,7 +56,7 @@ QUnit.module('Basic', {
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.ORIGINAL_THREAD_WINDOW_APPENDTO = this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO;
|
||||
|
||||
this.createParent = function (params) {
|
||||
this.createParent = async function (params) {
|
||||
var widget = new Widget();
|
||||
|
||||
// in non-debug mode, append thread windows in qunit-fixture
|
||||
@@ -68,7 +68,7 @@ QUnit.module('Basic', {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture';
|
||||
}
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, params);
|
||||
await testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
};
|
||||
},
|
||||
@@ -81,7 +81,7 @@ QUnit.module('Basic', {
|
||||
QUnit.test('basic rendering thread window', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -128,7 +128,7 @@ QUnit.test('basic rendering thread window', async function (assert) {
|
||||
QUnit.test('close thread window using ESCAPE key', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -169,7 +169,7 @@ QUnit.test('close thread window using ESCAPE key', async function (assert) {
|
||||
QUnit.test('thread window\'s input can still be focused when the UI is blocked', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -205,7 +205,7 @@ QUnit.test('thread window\'s input can still be focused when the UI is blocked',
|
||||
QUnit.test('emoji popover should open correctly in thread windows', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -227,7 +227,7 @@ QUnit.test('emoji popover should open correctly in thread windows', async functi
|
||||
QUnit.test('do not increase unread counter when receiving message with myself as author', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
session: { partner_id: 3 }
|
||||
@@ -274,7 +274,7 @@ QUnit.test('do not increment unread counter with focus on thread window', async
|
||||
// order to set the focus on it.
|
||||
assert.expect(2);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
session: { partner_id: 3 }
|
||||
@@ -322,7 +322,7 @@ QUnit.test('do not mark as read the newly open thread window from received messa
|
||||
message_unread_counter: 0,
|
||||
}];
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
session: { partner_id: 3 },
|
||||
@@ -393,7 +393,7 @@ QUnit.test('show document link of message linked to a document', async function
|
||||
channel_type: "public",
|
||||
});
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
session: { partner_id: 3 },
|
||||
@@ -510,7 +510,7 @@ QUnit.test('do not auto-focus chat window on receiving new message from new DM',
|
||||
state: 'open',
|
||||
}];
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
session: { partner_id: 3 },
|
||||
@@ -600,7 +600,7 @@ QUnit.test('no out-of-office status in thread window', async function (assert) {
|
||||
}],
|
||||
},
|
||||
};
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -650,7 +650,7 @@ QUnit.test('receive 2 new DM messages in quick succession (no chat window initia
|
||||
}],
|
||||
};
|
||||
|
||||
const parent = this.createParent({
|
||||
const parent = await this.createParent({
|
||||
data: this.data,
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'channel_minimize') {
|
||||
@@ -740,7 +740,7 @@ QUnit.test('non-deletable message attachments', async function (assert) {
|
||||
record_name: "general",
|
||||
res_id: 1,
|
||||
}];
|
||||
const parent = this.createParent({
|
||||
const parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -781,7 +781,7 @@ QUnit.test('join channel from click channel mention', async function (assert) {
|
||||
channel_ids: [1],
|
||||
});
|
||||
|
||||
const parent = this.createParent({
|
||||
const parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
session: { partner_id: 3 },
|
||||
|
||||
@@ -32,7 +32,7 @@ QUnit.module('Blank', {
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.ORIGINAL_THREAD_WINDOW_APPENDTO = this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO;
|
||||
|
||||
this.createParent = function (params) {
|
||||
this.createParent = async function (params) {
|
||||
var widget = new Widget();
|
||||
|
||||
// in non-debug mode, append thread windows in qunit-fixture
|
||||
@@ -44,7 +44,7 @@ QUnit.module('Blank', {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture';
|
||||
}
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, params);
|
||||
await testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@ QUnit.module('Blank', {
|
||||
QUnit.test('basic rendering blank thread window', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -117,7 +117,7 @@ QUnit.test('basic rendering blank thread window', async function (assert) {
|
||||
QUnit.test('close blank thread window', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -139,7 +139,7 @@ QUnit.test('fold blank thread window', async function (assert) {
|
||||
// (e.g. 400px)
|
||||
assert.expect(3);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -191,7 +191,7 @@ QUnit.test('open new DM chat from blank thread window', async function (assert)
|
||||
records: [],
|
||||
};
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -274,7 +274,7 @@ QUnit.test('open already detached DM chat from blank thread window', async funct
|
||||
name: 'DemoUser1',
|
||||
}];
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
|
||||
@@ -31,7 +31,7 @@ QUnit.module('Hidden', {
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.ORIGINAL_THREAD_WINDOW_APPENDTO = this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO;
|
||||
|
||||
this.createParent = function (params) {
|
||||
this.createParent = async function (params) {
|
||||
var widget = new Widget();
|
||||
|
||||
// in non-debug mode, append thread windows in qunit-fixture
|
||||
@@ -43,7 +43,7 @@ QUnit.module('Hidden', {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture';
|
||||
}
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, params);
|
||||
await testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
};
|
||||
},
|
||||
@@ -86,7 +86,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
},
|
||||
};
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -172,7 +172,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver
|
||||
},
|
||||
};
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
@@ -266,7 +266,7 @@ QUnit.test('receive message from hidden thread window', async function (assert)
|
||||
},
|
||||
};
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ QUnit.module('Moderation', {
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.ORIGINAL_THREAD_WINDOW_APPENDTO = this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO;
|
||||
|
||||
this.createParent = function (params) {
|
||||
this.createParent = async function (params) {
|
||||
var widget = new Widget();
|
||||
|
||||
// in non-debug mode, append thread windows in qunit-fixture
|
||||
@@ -74,7 +74,7 @@ QUnit.module('Moderation', {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture';
|
||||
}
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, params);
|
||||
await testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
};
|
||||
},
|
||||
@@ -110,7 +110,7 @@ QUnit.test('moderator: moderated channel with pending moderation message', async
|
||||
res_id: 1,
|
||||
}];
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ QUnit.module('Typing', {
|
||||
await testUtils.nextMicrotaskTick();
|
||||
};
|
||||
|
||||
this.createParent = function (params) {
|
||||
this.createParent = async function (params) {
|
||||
var widget = new Widget();
|
||||
|
||||
// in non-debug mode, append thread windows in qunit-fixture
|
||||
@@ -63,7 +63,7 @@ QUnit.module('Typing', {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture';
|
||||
}
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, params);
|
||||
await testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
};
|
||||
},
|
||||
@@ -76,7 +76,7 @@ QUnit.module('Typing', {
|
||||
QUnit.test('receive typing notification', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var parent = this.createParent({
|
||||
var parent = await this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
|
||||
@@ -10,7 +10,7 @@ QUnit.module('Mail DebugManager', {}, function () {
|
||||
QUnit.test("Manage Messages", async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var debugManager = createDebugManager({
|
||||
var debugManager = await createDebugManager({
|
||||
intercepts: {
|
||||
do_action: function (event) {
|
||||
assert.deepEqual(event.data.action, {
|
||||
|
||||
@@ -38,7 +38,7 @@ QUnit.test('note activity menu widget: create note from activity menu', async fu
|
||||
assert.expect(15);
|
||||
var self = this;
|
||||
var activityMenu = new ActivityMenu();
|
||||
testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
await testUtils.mock.addMockEnvironment(activityMenu, {
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'systray_get_activities') {
|
||||
|
||||
@@ -13,7 +13,7 @@ odoo.define('stock.stock_traceability_report_backend_tests', function (require)
|
||||
* @returns {Promise<StockReportGeneric>}
|
||||
*/
|
||||
async function createStockReportAction(params) {
|
||||
const parent = testUtils.createParent(params);
|
||||
const parent = await testUtils.createParent(params);
|
||||
const report = new StockReportGeneric(parent, params.action);
|
||||
const target = testUtils.prepareTarget(params.debug);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ var data_manager = require('web.data_manager');
|
||||
var dom = require('web.dom');
|
||||
var KeyboardNavigationMixin = require('web.KeyboardNavigationMixin');
|
||||
var Loading = require('web.Loading');
|
||||
var local_storage = require('web.local_storage');
|
||||
var RainbowMan = require('web.RainbowMan');
|
||||
var session = require('web.session');
|
||||
var utils = require('web.utils');
|
||||
@@ -103,7 +102,7 @@ var AbstractWebClient = Widget.extend(KeyboardNavigationMixin, {
|
||||
this.action_mutex = new concurrency.Mutex();
|
||||
this.set('title_part', {"zopenerp": "Odoo"});
|
||||
this.env = env;
|
||||
core.bus.on('legacy_webclient_request', this, this._onLegacyWebclientRequest);
|
||||
this.env.bus.on('set_title_part', this, this._onSetTitlePart);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -206,6 +205,11 @@ var AbstractWebClient = Widget.extend(KeyboardNavigationMixin, {
|
||||
set_action_manager: function () {
|
||||
var self = this;
|
||||
this.action_manager = new ActionManager(this, session.user_context);
|
||||
this.env.bus.on('do-action', this, payload => {
|
||||
this.action_manager.doAction(payload.action, payload.options)
|
||||
.then(payload.on_success || (() => {}))
|
||||
.guardedCatch(payload.on_fail || (() => {}));
|
||||
});
|
||||
var fragment = document.createDocumentFragment();
|
||||
return this.action_manager.appendTo(fragment).then(function () {
|
||||
dom.append(self.$el, fragment, {
|
||||
@@ -439,20 +443,6 @@ var AbstractWebClient = Widget.extend(KeyboardNavigationMixin, {
|
||||
_onGetScrollPosition: function (ev) {
|
||||
ev.data.callback(this.getScrollPosition());
|
||||
},
|
||||
/**
|
||||
* Services used to trigger_up some events (e.g. do_action, get_session,
|
||||
* set_title_part) when the webclient was still instantiating them. Now that
|
||||
* services have been moved to the env, the webclient is no longer their
|
||||
* parent and they can thus no longer communicate with the webclient by
|
||||
* trigger_up. Instead, they trigger those events on the bus, and we end up
|
||||
* in this handler. Eventually, services should stop triggering events up.
|
||||
*
|
||||
* @private
|
||||
* @param {CustomEvent} ev
|
||||
*/
|
||||
_onLegacyWebclientRequest: function (ev) {
|
||||
this._trigger_up(ev);
|
||||
},
|
||||
/**
|
||||
* Loads an action from the database given its ID.
|
||||
*
|
||||
@@ -502,13 +492,13 @@ var AbstractWebClient = Widget.extend(KeyboardNavigationMixin, {
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
* @param {string} ev.data.part
|
||||
* @param {string} [ev.data.title]
|
||||
* @param {Object} payload
|
||||
* @param {string} payload.part
|
||||
* @param {string} [payload.title]
|
||||
*/
|
||||
_onSetTitlePart: function (ev) {
|
||||
var part = ev.data.part;
|
||||
var title = ev.data.title;
|
||||
_onSetTitlePart: function (payload) {
|
||||
var part = payload.part;
|
||||
var title = payload.title;
|
||||
this.set_title_part(part, title);
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
odoo.define("web.commonEnv", function (require) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This file defines the common environment, which contains everything that
|
||||
* is needed in the env for both the backend and the frontend (Odoo
|
||||
* terminology). This module shouldn't be used as is. It should only be
|
||||
* imported by the module defining the final env to use (in the frontend or
|
||||
* in the backend). For instance, module 'web.env' imports it, adds stuff to
|
||||
* it, and exports the final env that is used by the whole webclient
|
||||
* application.
|
||||
*
|
||||
* There should be as much dependencies as possible in the env object. This
|
||||
* will allow an easier testing of components. See [1] for more information
|
||||
* on environments.
|
||||
*
|
||||
* [1] https://github.com/odoo/owl/blob/master/doc/reference/environment.md#content-of-an-environment
|
||||
*/
|
||||
|
||||
const { jsonRpc } = require("web.ajax");
|
||||
const { device, isDebug } = require("web.config");
|
||||
const { bus, serviceRegistry } = require("web.core");
|
||||
const rpc = require("web.rpc");
|
||||
const session = require("web.session");
|
||||
const { _t } = require("web.translation");
|
||||
const utils = require("web.utils");
|
||||
|
||||
|
||||
// Build the basic env
|
||||
const env = {
|
||||
_t,
|
||||
bus,
|
||||
device,
|
||||
isDebug,
|
||||
qweb: new owl.QWeb({ translateFn: _t }),
|
||||
services: {
|
||||
ajaxJsonRPC() {
|
||||
return jsonRpc(...arguments);
|
||||
},
|
||||
getCookie() {
|
||||
return utils.get_cookie(...arguments);
|
||||
},
|
||||
httpRequest(route, params = {}, readMethod = 'json') {
|
||||
const info = {
|
||||
method: params.method || 'POST',
|
||||
};
|
||||
if (params.method !== 'GET') {
|
||||
const formData = new FormData();
|
||||
for (const key in params) {
|
||||
if (key === 'method') {
|
||||
continue;
|
||||
}
|
||||
const value = params[key];
|
||||
if (Array.isArray(value) && value.length) {
|
||||
for (const val of value) {
|
||||
formData.append(key, val);
|
||||
}
|
||||
} else {
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
info.body = formData;
|
||||
}
|
||||
return fetch(route, info).then(response => response[readMethod]());
|
||||
},
|
||||
navigate(url, params) {
|
||||
window.location = $.param.querystring(url, params);
|
||||
},
|
||||
reloadPage() {
|
||||
window.location.reload();
|
||||
},
|
||||
rpc(params, options) {
|
||||
const query = rpc.buildQuery(params);
|
||||
return session.rpc(query.route, query.params, options);
|
||||
},
|
||||
setCookie() {
|
||||
utils.set_cookie(...arguments);
|
||||
},
|
||||
},
|
||||
session,
|
||||
};
|
||||
|
||||
|
||||
// Deploy services in the env (specializations of AbstractService registered
|
||||
// into the serviceRegistry)
|
||||
const UndeployedServices = Object.assign({}, serviceRegistry.map);
|
||||
function _deployServices() {
|
||||
let done = false;
|
||||
while (!done) {
|
||||
// find a service with no missing dependency
|
||||
const serviceName = Object.keys(UndeployedServices).find(serviceName => {
|
||||
const Service = UndeployedServices[serviceName];
|
||||
return Service.prototype.dependencies.every(depName => {
|
||||
return env.services[depName];
|
||||
});
|
||||
});
|
||||
if (serviceName) {
|
||||
const Service = UndeployedServices[serviceName];
|
||||
const service = new Service(env);
|
||||
env.services[serviceName] = service;
|
||||
delete UndeployedServices[serviceName];
|
||||
service.start();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
serviceRegistry.onAdd((serviceName, Service) => {
|
||||
if (serviceName in env.services || serviceName in UndeployedServices) {
|
||||
throw new Error(`Service ${serviceName} is already loaded.`);
|
||||
}
|
||||
UndeployedServices[serviceName] = Service;
|
||||
_deployServices();
|
||||
});
|
||||
_deployServices();
|
||||
|
||||
|
||||
return env;
|
||||
});
|
||||
@@ -7,14 +7,39 @@ var ServicesMixin = require('web.ServicesMixin');
|
||||
|
||||
var AbstractService = Class.extend(Mixins.EventDispatcherMixin, ServicesMixin, {
|
||||
dependencies: [],
|
||||
init: function (parent) {
|
||||
init: function (env) {
|
||||
Mixins.EventDispatcherMixin.init.call(this, arguments);
|
||||
this.setParent(parent);
|
||||
this.env = env;
|
||||
},
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
start: function () {},
|
||||
/**
|
||||
* Directly calls the requested service, instead of triggering a
|
||||
* 'call_service' event up, which wouldn't work as services have no parent
|
||||
*
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
_trigger_up: function (ev) {
|
||||
Mixins.EventDispatcherMixin._trigger_up.apply(this, arguments);
|
||||
if (ev.is_stopped()) {
|
||||
return;
|
||||
}
|
||||
const payload = ev.data;
|
||||
if (ev.name === 'call_service') {
|
||||
let args = payload.args || [];
|
||||
if (payload.service === 'ajax' && payload.method === 'rpc') {
|
||||
// ajax service uses an extra 'target' argument for rpc
|
||||
args = args.concat(ev.target);
|
||||
}
|
||||
const service = this.env.services[payload.service];
|
||||
const result = service[payload.method].apply(service, args);
|
||||
payload.callback(result);
|
||||
} else if (ev.name === 'do_action') {
|
||||
this.env.bus.trigger('do-action', payload);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return AbstractService;
|
||||
|
||||
@@ -3,6 +3,8 @@ odoo.define('web.ServiceProviderMixin', function (require) {
|
||||
|
||||
var core = require('web.core');
|
||||
|
||||
// ServiceProviderMixin is deprecated. It is only used by the ProjectTimesheet
|
||||
// app. As soon as it no longer uses it, we can remove it.
|
||||
var ServiceProviderMixin = {
|
||||
services: {}, // dict containing deployed service instances
|
||||
UndeployedServices: {}, // dict containing classes of undeployed services
|
||||
|
||||
@@ -1,157 +1,16 @@
|
||||
odoo.define("web.env", function (require) {
|
||||
"use strict";
|
||||
|
||||
const { jsonRpc } = require('web.ajax');
|
||||
const { device, isDebug } = require("web.config");
|
||||
const { bus, serviceRegistry } = require("web.core");
|
||||
/**
|
||||
* This file defines the env to use in the webclient.
|
||||
*/
|
||||
|
||||
const commonEnv = require('web.commonEnv');
|
||||
const dataManager = require('web.data_manager');
|
||||
const { blockUI, unblockUI } = require("web.framework");
|
||||
const rpc = require("web.rpc");
|
||||
const session = require("web.session");
|
||||
const { _t } = require('web.translation');
|
||||
const utils = require("web.utils");
|
||||
|
||||
const qweb = new owl.QWeb({ translateFn: _t });
|
||||
const env = Object.assign(commonEnv, { dataManager });
|
||||
env.services = Object.assign(env.services, { blockUI, unblockUI });
|
||||
|
||||
function ajaxJsonRPC() {
|
||||
return jsonRpc(...arguments);
|
||||
}
|
||||
|
||||
function getCookie() {
|
||||
return utils.get_cookie(...arguments);
|
||||
}
|
||||
|
||||
function httpRequest(route, params = {}, readMethod = 'json') {
|
||||
const info = {
|
||||
method: params.method || 'POST',
|
||||
};
|
||||
if (params.method !== 'GET') {
|
||||
const formData = new FormData();
|
||||
for (const key in params) {
|
||||
if (key === 'method') {
|
||||
continue;
|
||||
}
|
||||
const value = params[key];
|
||||
if (Array.isArray(value) && value.length) {
|
||||
for (const val of value) {
|
||||
formData.append(key, val);
|
||||
}
|
||||
} else {
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
info.body = formData;
|
||||
}
|
||||
|
||||
return fetch(route, info).then(response => response[readMethod]());
|
||||
}
|
||||
|
||||
function navigate(url, params) {
|
||||
window.location = $.param.querystring(url, params);
|
||||
}
|
||||
|
||||
function performRPC(params, options) {
|
||||
const query = rpc.buildQuery(params);
|
||||
return session.rpc(query.route, query.params, options);
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function setCookie() {
|
||||
utils.set_cookie(...arguments);
|
||||
}
|
||||
|
||||
// ServiceProvider
|
||||
const services = {}; // dict containing deployed service instances
|
||||
const UndeployedServices = {}; // dict containing classes of undeployed services
|
||||
function _deployServices() {
|
||||
let done = false;
|
||||
while (!done) {
|
||||
const serviceName = _.findKey(UndeployedServices, Service => {
|
||||
// no missing dependency
|
||||
return !_.some(Service.prototype.dependencies, depName => {
|
||||
return !services[depName];
|
||||
});
|
||||
});
|
||||
if (serviceName) {
|
||||
const Service = UndeployedServices[serviceName];
|
||||
// we created a patched version of the Service in which the 'trigger_up'
|
||||
// function directly calls the requested service, instead of triggering
|
||||
// a 'call_service' event up, which wouldn't work as services have
|
||||
// no parent
|
||||
const PatchedService = Service.extend({
|
||||
_trigger_up: function (ev) {
|
||||
this._super(...arguments);
|
||||
if (!ev.is_stopped() && ev.name === 'call_service') {
|
||||
const payload = ev.data;
|
||||
let args = payload.args || [];
|
||||
if (payload.service === 'ajax' && payload.method === 'rpc') {
|
||||
// ajax service uses an extra 'target' argument for rpc
|
||||
args = args.concat(ev.target);
|
||||
}
|
||||
const service = services[payload.service];
|
||||
const result = service[payload.method].apply(service, args);
|
||||
payload.callback(result);
|
||||
} else {
|
||||
// historically, some services could reach the webclient
|
||||
// by triggering events up, as the webclient was their
|
||||
// parent. Since services have been moved to the env,
|
||||
// this is no longer the case, so we re-trigger those
|
||||
// events on the bus for now. Eventually, services
|
||||
// should stop triggering events up (they can still
|
||||
// communicate with other services through the env).
|
||||
bus.trigger('legacy_webclient_request', ev);
|
||||
}
|
||||
},
|
||||
});
|
||||
const service = new PatchedService();
|
||||
services[serviceName] = service;
|
||||
delete UndeployedServices[serviceName];
|
||||
service.start();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_.each(serviceRegistry.map, (Service, serviceName) => {
|
||||
if (serviceName in UndeployedServices) {
|
||||
throw new Error(`Service ${serviceName} is already loaded.`);
|
||||
}
|
||||
UndeployedServices[serviceName] = Service;
|
||||
});
|
||||
serviceRegistry.onAdd((serviceName, Service) => {
|
||||
if (serviceName in services || serviceName in UndeployedServices) {
|
||||
throw new Error(`Service ${serviceName} is already loaded.`);
|
||||
}
|
||||
UndeployedServices[serviceName] = Service;
|
||||
_deployServices();
|
||||
});
|
||||
_deployServices();
|
||||
|
||||
// There should be as much dependencies as possible in the env object.
|
||||
// This will allow an easier testing of components.
|
||||
// See https://github.com/odoo/owl/blob/master/doc/reference/environment.md#content-of-an-environment
|
||||
// for more information on environments.
|
||||
return {
|
||||
_t,
|
||||
bus,
|
||||
dataManager,
|
||||
device,
|
||||
isDebug,
|
||||
qweb,
|
||||
services: Object.assign(services, {
|
||||
ajaxJsonRPC,
|
||||
blockUI,
|
||||
getCookie,
|
||||
httpRequest,
|
||||
navigate,
|
||||
reloadPage,
|
||||
rpc: performRPC,
|
||||
setCookie,
|
||||
unblockUI,
|
||||
}),
|
||||
session,
|
||||
};
|
||||
return env;
|
||||
});
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
odoo.define("web.public_env", function (require) {
|
||||
"use strict";
|
||||
|
||||
const { _t } = require("web.core");
|
||||
const rpc = require("web.rpc");
|
||||
/**
|
||||
* This file defines the env to use in the public side.
|
||||
*/
|
||||
|
||||
const qweb = new owl.QWeb({ translateFn: _t });
|
||||
const commonEnv = require("web.commonEnv");
|
||||
|
||||
function performRPC(params, options) {
|
||||
const query = rpc.buildQuery(params);
|
||||
return session.rpc(query.route, query.params, options);
|
||||
}
|
||||
|
||||
// There should be as much dependencies as possible in the env object.
|
||||
// This will allow an easier testing of components.
|
||||
// See https://github.com/odoo/owl/blob/master/doc/reference/environment.md#content-of-an-environment
|
||||
// for more information on environments.
|
||||
return {
|
||||
qweb,
|
||||
services: {
|
||||
rpc: performRPC,
|
||||
},
|
||||
};
|
||||
return commonEnv;
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ odoo.define('web.public.root', function (require) {
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
var dom = require('web.dom');
|
||||
var ServiceProviderMixin = require('web.ServiceProviderMixin');
|
||||
const env = require('web.public_env');
|
||||
var session = require('web.session');
|
||||
var utils = require('web.utils');
|
||||
var publicWidget = require('web.public.widget');
|
||||
@@ -25,16 +25,17 @@ var localeDef = ajax.loadJS('/web/webclient/locale/' + lang.replace('-', '_'));
|
||||
* this Class instance. Its main role will be to retrieve RPC demands from its
|
||||
* children and handle them.
|
||||
*/
|
||||
var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
|
||||
var PublicRoot = publicWidget.RootWidget.extend({
|
||||
events: _.extend({}, publicWidget.RootWidget.prototype.events || {}, {
|
||||
'submit .js_website_submit_form': '_onWebsiteFormSubmit',
|
||||
'click .js_disable_on_click': '_onDisableOnClick',
|
||||
}),
|
||||
custom_events: _.extend({}, publicWidget.RootWidget.prototype.custom_events || {}, {
|
||||
'context_get': '_onContextGet',
|
||||
'main_object_request': '_onMainObjectRequest',
|
||||
'widgets_start_request': '_onWidgetsStartRequest',
|
||||
'widgets_stop_request': '_onWidgetsStopRequest',
|
||||
call_service: '_onCallService',
|
||||
context_get: '_onContextGet',
|
||||
main_object_request: '_onMainObjectRequest',
|
||||
widgets_start_request: '_onWidgetsStartRequest',
|
||||
widgets_stop_request: '_onWidgetsStopRequest',
|
||||
}),
|
||||
|
||||
/**
|
||||
@@ -42,7 +43,7 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
ServiceProviderMixin.init.call(this);
|
||||
this.env = env;
|
||||
this.publicWidgets = [];
|
||||
},
|
||||
/**
|
||||
@@ -90,37 +91,6 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Automatically adds the global context to RPCs.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_call_service: function (ev) {
|
||||
if (ev.data.service === 'ajax' && ev.data.method === 'rpc') {
|
||||
var route = ev.data.args[0];
|
||||
if (_.str.startsWith(route, '/web/dataset/call_kw/')) {
|
||||
var params = ev.data.args[1];
|
||||
var options = ev.data.args[2];
|
||||
var noContextKeys = undefined;
|
||||
if (options) {
|
||||
noContextKeys = options.noContextKeys;
|
||||
ev.data.args[2] = _.omit(options, 'noContextKeys');
|
||||
}
|
||||
params.kwargs.context = _computeContext.call(this, params.kwargs.context, noContextKeys);
|
||||
}
|
||||
} else if (ev.data.service === 'ajax' && ev.data.method === 'loadLibs') {
|
||||
ev.data.args[1] = _computeContext.call(this, ev.data.args[1]);
|
||||
}
|
||||
return ServiceProviderMixin._call_service.apply(this, arguments);
|
||||
|
||||
function _computeContext(context, noContextKeys) {
|
||||
context = _.extend({}, this._getContext(), context);
|
||||
if (noContextKeys) {
|
||||
context = _.omit(context, noContextKeys);
|
||||
}
|
||||
return JSON.parse(JSON.stringify(context));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Retrieves the global context of the public environment. This is the
|
||||
* context which is automatically added to each RPC.
|
||||
@@ -234,6 +204,47 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Calls the requested service from the env. Automatically adds the global
|
||||
* context to RPCs.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onCallService: function (ev) {
|
||||
function _computeContext(context, noContextKeys) {
|
||||
context = _.extend({}, this._getContext(), context);
|
||||
if (noContextKeys) {
|
||||
context = _.omit(context, noContextKeys);
|
||||
}
|
||||
return JSON.parse(JSON.stringify(context));
|
||||
}
|
||||
|
||||
const payload = ev.data;
|
||||
let args = payload.args || [];
|
||||
if (payload.service === 'ajax' && payload.method === 'rpc') {
|
||||
// ajax service uses an extra 'target' argument for rpc
|
||||
args = args.concat(ev.target);
|
||||
|
||||
var route = args[0];
|
||||
if (_.str.startsWith(route, '/web/dataset/call_kw/')) {
|
||||
var params = args[1];
|
||||
var options = args[2];
|
||||
var noContextKeys;
|
||||
if (options) {
|
||||
noContextKeys = options.noContextKeys;
|
||||
args[2] = _.omit(options, 'noContextKeys');
|
||||
}
|
||||
params.kwargs.context = _computeContext.call(this, params.kwargs.context, noContextKeys);
|
||||
}
|
||||
} else if (payload.service === 'ajax' && payload.method === 'loadLibs') {
|
||||
args[1] = _computeContext.call(this, args[1]);
|
||||
}
|
||||
|
||||
const service = this.env.services[payload.service];
|
||||
const result = service[payload.method].apply(service, args);
|
||||
payload.callback(result);
|
||||
},
|
||||
/**
|
||||
* Called when someone asked for the global public context.
|
||||
*
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
odoo.define('root.widget', function (require) {
|
||||
'use strict';
|
||||
|
||||
const env = require('web.public_env');
|
||||
var lazyloader = require('web.public.lazyloader');
|
||||
var rootData = require('web.public.root');
|
||||
|
||||
/**
|
||||
* Configure Owl with the public env
|
||||
*/
|
||||
owl.config.mode = env.isDebug() ? "dev" : "prod";
|
||||
owl.Component.env = env;
|
||||
|
||||
/**
|
||||
* This widget is important, because the tour manager needs a root widget in
|
||||
* order to work. The root widget must be a service provider with the ajax
|
||||
|
||||
@@ -26,7 +26,7 @@ QUnit.module('KeyboardNavigationMixin', function () {
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
var parent = testUtils.createParent({});
|
||||
var parent = await testUtils.createParent({});
|
||||
var w = new KeyboardWidget(parent);
|
||||
await w.appendTo($target);
|
||||
|
||||
@@ -67,7 +67,7 @@ QUnit.module('KeyboardNavigationMixin', function () {
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
var parent = testUtils.createParent({});
|
||||
var parent = await testUtils.createParent({});
|
||||
var w = new KeyboardWidget(parent);
|
||||
await w.appendTo($target);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ odoo.define('web.menu_tests', function (require) {
|
||||
QUnit.test('Systray on_attach_callback is called', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const parent = testUtils.createParent({});
|
||||
const parent = await testUtils.createParent({});
|
||||
|
||||
// Add some widgets to the systray
|
||||
const Widget1 = Widget.extend({
|
||||
@@ -22,7 +22,7 @@ odoo.define('web.menu_tests', function (require) {
|
||||
const Widget2 = Widget.extend({
|
||||
on_attach_callback: () => assert.step('on_attach_callback widget2')
|
||||
});
|
||||
SystrayMenu.Items = [Widget1, Widget2]
|
||||
SystrayMenu.Items = [Widget1, Widget2];
|
||||
|
||||
testUtils.mock.patch(SystrayMenu, {
|
||||
on_attach_callback: function () {
|
||||
|
||||
@@ -7,8 +7,7 @@ odoo.define('web.systray_tests', function (require) {
|
||||
|
||||
QUnit.test('Adding async components to the registry respects the sequence', async function (assert) {
|
||||
assert.expect(2);
|
||||
var parent = testUtils.createParent({
|
||||
});
|
||||
var parent = await testUtils.createParent({});
|
||||
var prom = testUtils.makeTestPromise();
|
||||
|
||||
var synchronousFirstWidget = Widget.extend({
|
||||
|
||||
@@ -13,7 +13,7 @@ QUnit.module('chrome', {}, function () {
|
||||
|
||||
var parent = new Widget();
|
||||
|
||||
testUtils.mock.addMockEnvironment(parent, {});
|
||||
await testUtils.mock.addMockEnvironment(parent, {});
|
||||
var userMenu = new UserMenu(parent);
|
||||
await userMenu.appendTo($('body'));
|
||||
|
||||
|
||||
@@ -6,21 +6,10 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
|
||||
const { Model } = require('web.model');
|
||||
const pyUtils = require('web.py_utils');
|
||||
const testUtils = require('web.test_utils');
|
||||
const session = require('web.session');
|
||||
|
||||
const cpHelpers = testUtils.controlPanel;
|
||||
const { createComponent } = testUtils;
|
||||
|
||||
function patchSession(newSession) {
|
||||
// We have to patch the "legacy" session because field_utils is using it.
|
||||
// TODO: remove it when the field_utils are re-written.
|
||||
const initialSession = session;
|
||||
Object.assign(session, newSession);
|
||||
return function () {
|
||||
Object.assign(session, initialSession);
|
||||
};
|
||||
}
|
||||
|
||||
QUnit.module('Components', {
|
||||
beforeEach: function () {
|
||||
this.fields = {
|
||||
@@ -203,11 +192,6 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
|
||||
QUnit.test('custom filter datetime with equal operator', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
patchSession({
|
||||
getTZOffset: function () {
|
||||
return -240;
|
||||
},
|
||||
});
|
||||
class MockedControlPanelModel extends Model {
|
||||
createNewFilters(preFilters) {
|
||||
const preFilter = preFilters[0];
|
||||
@@ -224,6 +208,11 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
|
||||
props: {
|
||||
fields: this.fields,
|
||||
},
|
||||
session: {
|
||||
getTZOffset() {
|
||||
return -240;
|
||||
},
|
||||
},
|
||||
env: { controlPanelModel },
|
||||
});
|
||||
|
||||
@@ -243,11 +232,6 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
|
||||
QUnit.test('custom filter datetime between operator', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
patchSession({
|
||||
getTZOffset: function () {
|
||||
return -240;
|
||||
},
|
||||
});
|
||||
class MockedControlPanelModel extends Model {
|
||||
createNewFilters(preFilters) {
|
||||
const preFilter = preFilters[0];
|
||||
@@ -265,6 +249,11 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
|
||||
props: {
|
||||
fields: this.fields,
|
||||
},
|
||||
session: {
|
||||
getTZOffset() {
|
||||
return -240;
|
||||
},
|
||||
},
|
||||
env: { controlPanelModel },
|
||||
});
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ var Widget = require('web.Widget');
|
||||
|
||||
var ESCAPE_KEY = $.Event("keyup", { which: 27 });
|
||||
|
||||
function createEmptyParent(debug) {
|
||||
async function createEmptyParent(debug) {
|
||||
var widget = new Widget();
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, {
|
||||
await testUtils.mock.addMockEnvironment(widget, {
|
||||
debug: debug || false,
|
||||
});
|
||||
return widget;
|
||||
@@ -24,7 +24,7 @@ QUnit.module('core', {}, function () {
|
||||
assert.expect(3);
|
||||
|
||||
var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'custom callback');
|
||||
var parent = createEmptyParent();
|
||||
var parent = await createEmptyParent();
|
||||
new Dialog(parent, {
|
||||
buttons: [
|
||||
{
|
||||
@@ -54,7 +54,7 @@ QUnit.module('core', {}, function () {
|
||||
assert.expect(3);
|
||||
|
||||
var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'custom callback');
|
||||
var parent = createEmptyParent();
|
||||
var parent = await createEmptyParent();
|
||||
new Dialog(parent, {
|
||||
buttons: [
|
||||
{
|
||||
@@ -84,7 +84,7 @@ QUnit.module('core', {}, function () {
|
||||
assert.expect(3);
|
||||
|
||||
var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'confirm callback');
|
||||
var parent = createEmptyParent();
|
||||
var parent = await createEmptyParent();
|
||||
var options = {
|
||||
confirm_callback: testPromise.reject,
|
||||
cancel_callback: testPromise.resolve,
|
||||
@@ -107,7 +107,7 @@ QUnit.module('core', {}, function () {
|
||||
assert.expect(3);
|
||||
|
||||
var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'alert callback');
|
||||
var parent = createEmptyParent();
|
||||
var parent = await createEmptyParent();
|
||||
var options = {
|
||||
confirm_callback: testPromise.resolve,
|
||||
};
|
||||
|
||||
@@ -402,7 +402,7 @@ QUnit.module('core', {}, function () {
|
||||
|
||||
var def;
|
||||
var parent = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parent, {
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
session: {
|
||||
rpc: function () {
|
||||
def = testUtils.makeTestPromise();
|
||||
|
||||
@@ -1060,7 +1060,7 @@ QUnit.module('fields', {}, function () {
|
||||
var fixture = $('#qunit-fixture');
|
||||
var self = this;
|
||||
|
||||
var model = testUtils.createModel({
|
||||
var model = await testUtils.createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1083,7 +1083,7 @@ QUnit.module('fields', {}, function () {
|
||||
});
|
||||
var parent = new StandaloneWidget(model);
|
||||
model.setParent(parent);
|
||||
testUtils.mock.addMockEnvironment(parent, {
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: self.data,
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(args.method);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
odoo.define('web.test_env', async function (require) {
|
||||
"use strict";
|
||||
|
||||
const AbstractStorageService = require('web.AbstractStorageService');
|
||||
const Bus = require("web.Bus");
|
||||
const RamStorage = require('web.RamStorage');
|
||||
const { buildQuery } = require("web.rpc");
|
||||
const Bus = require('web.Bus');
|
||||
const { buildQuery } = require('web.rpc');
|
||||
const session = require('web.session');
|
||||
|
||||
/**
|
||||
@@ -17,9 +15,6 @@ odoo.define('web.test_env', async function (require) {
|
||||
* @returns {Proxy}
|
||||
*/
|
||||
function makeTestEnvironment(env = {}, providedRPC = null) {
|
||||
const RamStorageService = AbstractStorageService.extend({
|
||||
storage: new RamStorage(),
|
||||
});
|
||||
const database = {
|
||||
parameters: {
|
||||
code: "en_US",
|
||||
@@ -31,33 +26,26 @@ odoo.define('web.test_env', async function (require) {
|
||||
time_format: '%H:%M:%S',
|
||||
},
|
||||
};
|
||||
let testEnv = {};
|
||||
const defaultEnv = {
|
||||
_t: env._t || Object.assign((s => s), { database }),
|
||||
bus: new Bus(),
|
||||
bus: env.bus || new Bus(),
|
||||
device: Object.assign({ isMobile: false }, env.device),
|
||||
isDebug: env.isDebug || (() => false),
|
||||
qweb: new owl.QWeb({ templates: session.owlTemplates }),
|
||||
services: Object.assign({
|
||||
ajax: { // for legacy subwidgets
|
||||
ajax: {
|
||||
rpc() {
|
||||
const prom = testEnv.session.rpc(...arguments);
|
||||
prom.abort = function () {
|
||||
throw new Error("Can't abort this request");
|
||||
};
|
||||
return prom;
|
||||
},
|
||||
return env.session.rpc(...arguments); // Compatibility Legacy Widgets
|
||||
}
|
||||
},
|
||||
getCookie() { },
|
||||
httpRequest() {
|
||||
getCookie() {},
|
||||
httpRequest(/* route, params = {}, readMethod = 'json' */) {
|
||||
return Promise.resolve('');
|
||||
},
|
||||
rpc(params, options) {
|
||||
const query = buildQuery(params);
|
||||
return testEnv.session.rpc(query.route, query.params, options);
|
||||
return env.session.rpc(query.route, query.params, options);
|
||||
},
|
||||
local_storage: new RamStorageService(),
|
||||
session_storage: new RamStorageService(),
|
||||
notification: { notify() { } },
|
||||
}, env.services),
|
||||
session: Object.assign({
|
||||
@@ -67,10 +55,10 @@ odoo.define('web.test_env', async function (require) {
|
||||
}
|
||||
throw new Error(`No method to perform RPC`);
|
||||
},
|
||||
url: session.url,
|
||||
}, env.session),
|
||||
};
|
||||
testEnv = Object.assign(env, defaultEnv);
|
||||
return testEnv;
|
||||
return Object.assign(env, defaultEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,7 +121,7 @@ odoo.define('web.test_utils', async function (require) {
|
||||
return {
|
||||
mock: {
|
||||
addMockEnvironment: testUtilsMock.addMockEnvironment,
|
||||
getMockedOwlEnv: testUtilsMock.getMockedOwlEnv,
|
||||
addMockEnvironmentOwl: testUtilsMock.addMockEnvironmentOwl,
|
||||
intercept: testUtilsMock.intercept,
|
||||
patch: testUtilsMock.patch,
|
||||
patchDate: testUtilsMock.patchDate,
|
||||
|
||||
@@ -67,7 +67,6 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
}
|
||||
|
||||
params.server = mockServer;
|
||||
Component.env = testUtilsMock.getMockedOwlEnv(params);
|
||||
|
||||
const userContext = params.context && params.context.user_context || {};
|
||||
const actionManager = new ActionManager(widget, userContext);
|
||||
@@ -142,7 +141,7 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
if (!(constructor.prototype instanceof Component)) {
|
||||
throw new Error(`Argument "constructor" must be an Owl Component.`);
|
||||
}
|
||||
const env = Object.assign(testUtilsMock.getMockedOwlEnv(params), params.env);
|
||||
const cleanUp = await testUtilsMock.addMockEnvironmentOwl(Component, params);
|
||||
class Parent extends Component {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
@@ -154,7 +153,6 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Parent.env = env;
|
||||
Parent.template = xml`<t t-component="Component" t-props="state" t-ref="component"/>`;
|
||||
const parent = new Parent();
|
||||
await parent.mount(prepareTarget(params.debug), { position: 'first-child' });
|
||||
@@ -162,6 +160,7 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
const originalDestroy = child.destroy;
|
||||
child.destroy = function () {
|
||||
child.destroy = originalDestroy;
|
||||
cleanUp();
|
||||
parent.destroy();
|
||||
};
|
||||
return child;
|
||||
@@ -241,9 +240,9 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
* mock method, assuming that the user has access rights, and is an admin.
|
||||
*
|
||||
* @param {Object} [params={}]
|
||||
* @returns {DebugManager}
|
||||
* @returns {Promise<DebugManager>}
|
||||
*/
|
||||
function createDebugManager(params = {}) {
|
||||
async function createDebugManager(params = {}) {
|
||||
const mockRPC = params.mockRPC;
|
||||
Object.assign(params, {
|
||||
async mockRPC(route, args) {
|
||||
@@ -268,7 +267,7 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
},
|
||||
});
|
||||
const debugManager = new DebugManager();
|
||||
testUtilsMock.addMockEnvironment(debugManager, params);
|
||||
await testUtilsMock.addMockEnvironment(debugManager, params);
|
||||
return debugManager;
|
||||
}
|
||||
|
||||
@@ -280,12 +279,12 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
* @param {Class} params.Model the model class to use
|
||||
* @returns {Model}
|
||||
*/
|
||||
function createModel(params) {
|
||||
async function createModel(params) {
|
||||
const widget = new Widget();
|
||||
|
||||
const model = new params.Model(widget);
|
||||
|
||||
testUtilsMock.addMockEnvironment(widget, params);
|
||||
await testUtilsMock.addMockEnvironment(widget, params);
|
||||
|
||||
// override the model's 'destroy' so that it calls 'destroy' on the widget
|
||||
// instead, as the widget is the parent of the model and the mockServer.
|
||||
@@ -304,11 +303,11 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
*
|
||||
* @param {Object} params This object will be given to addMockEnvironment, so
|
||||
* any parameters from that method applies
|
||||
* @returns {Widget}
|
||||
* @returns {Promise<Widget>}
|
||||
*/
|
||||
function createParent(params) {
|
||||
async function createParent(params) {
|
||||
const widget = new Widget();
|
||||
testUtilsMock.addMockEnvironment(widget, params);
|
||||
await testUtilsMock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
}
|
||||
|
||||
@@ -358,8 +357,6 @@ odoo.define('web.test_utils_create', function (require) {
|
||||
const viewInfo = testUtilsMock.fieldsViewGet(mockServer, params);
|
||||
|
||||
params.server = mockServer;
|
||||
const env = Object.assign(testUtilsMock.getMockedOwlEnv(params));
|
||||
Component.env = env;
|
||||
|
||||
// create the view
|
||||
const View = params.View;
|
||||
|
||||
@@ -10,12 +10,16 @@ odoo.define('web.test_utils_mock', function (require) {
|
||||
* testUtils file.
|
||||
*/
|
||||
|
||||
const AbstractStorageService = require('web.AbstractStorageService');
|
||||
const AjaxService = require('web.AjaxService');
|
||||
const basic_fields = require('web.basic_fields');
|
||||
const Bus = require('web.Bus');
|
||||
const config = require('web.config');
|
||||
const core = require('web.core');
|
||||
const dom = require('web.dom');
|
||||
const makeTestEnvironment = require('web.test_env');
|
||||
const MockServer = require('web.MockServer');
|
||||
const RamStorage = require('web.RamStorage');
|
||||
const session = require('web.session');
|
||||
|
||||
const DebouncedField = basic_fields.DebouncedField;
|
||||
@@ -25,6 +29,199 @@ const DebouncedField = basic_fields.DebouncedField;
|
||||
// Private functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a mocked environment to be used by OWL components in tests, with
|
||||
* requested services (+ ajax, local_storage and session_storage) deployed.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} params
|
||||
* @param {Bus} [params.bus]
|
||||
* @param {boolean} [params.debug]
|
||||
* @param {Object} [params.env]
|
||||
* @param {Bus} [params.env.bus]
|
||||
* @param {Object} [params.env.dataManager]
|
||||
* @param {Object} [params.env.services]
|
||||
* @param {Object[]} [params.favoriteFilters]
|
||||
* @param {Object} [params.services]
|
||||
* @param {Object} [params.session]
|
||||
* @param {MockServer} [mockServer]
|
||||
* @returns {Promise<Object>} env
|
||||
*/
|
||||
async function _getMockedOwlEnv(params, mockServer) {
|
||||
params.env = params.env || {};
|
||||
|
||||
// build the env
|
||||
const favoriteFilters = params.favoriteFilters;
|
||||
const debug = params.debug;
|
||||
const services = {};
|
||||
const env = Object.assign({}, params.env, {
|
||||
bus: params.bus || params.env.bus || new Bus(),
|
||||
dataManager: Object.assign({
|
||||
load_action: (actionID, context) => {
|
||||
return mockServer.performRpc('/web/action/load', {
|
||||
action_id: actionID,
|
||||
additional_context: context,
|
||||
});
|
||||
},
|
||||
load_views: (params, options) => {
|
||||
return mockServer.performRpc('/web/dataset/call_kw/' + params.model, {
|
||||
args: [],
|
||||
kwargs: {
|
||||
context: params.context,
|
||||
options: options,
|
||||
views: params.views_descr,
|
||||
},
|
||||
method: 'load_views',
|
||||
model: params.model,
|
||||
}).then(function (views) {
|
||||
views = _.mapObject(views, viewParams => {
|
||||
return fieldsViewGet(mockServer, viewParams);
|
||||
});
|
||||
if (favoriteFilters && 'search' in views) {
|
||||
views.search.favoriteFilters = favoriteFilters;
|
||||
}
|
||||
return views;
|
||||
});
|
||||
},
|
||||
load_filters: params => {
|
||||
if (debug) {
|
||||
console.log('[mock] load_filters', params);
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
}, params.env.dataManager),
|
||||
services: Object.assign(services, params.env.services),
|
||||
session: params.session || {},
|
||||
});
|
||||
|
||||
// deploy services into the env
|
||||
// determine services to instantiate (classes), and already register function services
|
||||
const servicesToDeploy = {};
|
||||
for (const name in params.services || {}) {
|
||||
const Service = params.services[name];
|
||||
if (Service.constructor.name === 'Class') {
|
||||
servicesToDeploy[name] = Service;
|
||||
} else {
|
||||
services[name] = Service;
|
||||
}
|
||||
}
|
||||
// always deploy ajax, local storage and session storage
|
||||
if (!servicesToDeploy.ajax) {
|
||||
const MockedAjaxService = AjaxService.extend({
|
||||
rpc: mockServer.performRpc.bind(mockServer),
|
||||
});
|
||||
services.ajax = new MockedAjaxService(env);
|
||||
}
|
||||
const RamStorageService = AbstractStorageService.extend({
|
||||
storage: new RamStorage(),
|
||||
});
|
||||
if (!servicesToDeploy.local_storage) {
|
||||
services.local_storage = new RamStorageService(env);
|
||||
}
|
||||
if (!servicesToDeploy.session_storage) {
|
||||
services.session_storage = new RamStorageService(env);
|
||||
}
|
||||
// deploy other requested services
|
||||
let done = false;
|
||||
while (!done) {
|
||||
const serviceName = Object.keys(servicesToDeploy).find(serviceName => {
|
||||
const Service = servicesToDeploy[serviceName];
|
||||
return Service.prototype.dependencies.every(depName => {
|
||||
return env.services[depName];
|
||||
});
|
||||
});
|
||||
if (serviceName) {
|
||||
const Service = servicesToDeploy[serviceName];
|
||||
services[serviceName] = new Service(env);
|
||||
delete servicesToDeploy[serviceName];
|
||||
services[serviceName].start();
|
||||
} else {
|
||||
const serviceNames = _.keys(servicesToDeploy);
|
||||
if (serviceNames.length) {
|
||||
console.warn("Non loaded services:", serviceNames);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
// wait for asynchronous services to properly start
|
||||
await new Promise(setTimeout);
|
||||
|
||||
return env;
|
||||
}
|
||||
/**
|
||||
* This function is used to mock global objects (session, config...) in tests.
|
||||
* It is necessary for legacy widgets. It returns a cleanUp function to call at
|
||||
* the end of the test.
|
||||
*
|
||||
* The function could be removed as soon as we do not support legacy widgets
|
||||
* anymore.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} params
|
||||
* @param {Object} [params.config] if given, it is used to extend the global
|
||||
* config,
|
||||
* @param {Object} [params.session] if given, it is used to extend the current,
|
||||
* real session.
|
||||
* @param {Object} [params.translateParameters] if given, it will be used to
|
||||
* extend the core._t.database.parameters object.
|
||||
* @returns {function} a cleanUp function to restore everything, to call at the
|
||||
* end of the test
|
||||
*/
|
||||
function _mockGlobalObjects(params) {
|
||||
// patch session
|
||||
let initialSession = Object.assign({}, session);
|
||||
session.getTZOffset = function () {
|
||||
return 0; // by default, but may be overridden in specific tests
|
||||
};
|
||||
if ('session' in params) {
|
||||
Object.assign(session, params.session);
|
||||
}
|
||||
|
||||
// patch config
|
||||
let initialConfig;
|
||||
if ('config' in params) {
|
||||
initialConfig = Object.assign({}, config);
|
||||
initialConfig.device = Object.assign({}, config.device);
|
||||
if ('device' in params.config) {
|
||||
Object.assign(config.device, params.config.device);
|
||||
}
|
||||
if ('debug' in params.config) {
|
||||
odoo.debug = params.config.debug;
|
||||
}
|
||||
}
|
||||
|
||||
// patch translate params
|
||||
let initialParameters;
|
||||
if ('translateParameters' in params) {
|
||||
initialParameters = Object.assign({}, core._t.database.parameters);
|
||||
Object.assign(core._t.database.parameters, params.translateParameters);
|
||||
}
|
||||
|
||||
// build the cleanUp function to restore everything at the end of the test
|
||||
function cleanUp() {
|
||||
let key;
|
||||
if ('session' in params) {
|
||||
for (key in session) {
|
||||
delete session[key];
|
||||
}
|
||||
}
|
||||
Object.assign(session, initialSession);
|
||||
if ('config' in params) {
|
||||
for (key in config) {
|
||||
delete config[key];
|
||||
}
|
||||
_.extend(config, initialConfig);
|
||||
}
|
||||
if ('translateParameters' in params) {
|
||||
for (key in core._t.database.parameters) {
|
||||
delete core._t.database.parameters[key];
|
||||
}
|
||||
_.extend(core._t.database.parameters, initialParameters);
|
||||
}
|
||||
}
|
||||
|
||||
return cleanUp;
|
||||
}
|
||||
/**
|
||||
* logs all event going through the target widget.
|
||||
*
|
||||
@@ -42,16 +239,58 @@ function _observe(widget) {
|
||||
// Public functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* performs a fields_view_get, and mocks the postprocessing done by the
|
||||
* data_manager to return an equivalent structure.
|
||||
*
|
||||
* @param {MockServer} server
|
||||
* @param {Object} params
|
||||
* @param {string} params.model
|
||||
* @returns {Object} an object with 3 keys: arch, fields and viewFields
|
||||
*/
|
||||
function fieldsViewGet(server, params) {
|
||||
var fieldsView = server.fieldsViewGet(params);
|
||||
// mock the structure produced by the DataManager
|
||||
fieldsView.viewFields = fieldsView.fields;
|
||||
fieldsView.fields = server.fieldsGet(params.model);
|
||||
return fieldsView;
|
||||
}
|
||||
|
||||
/**
|
||||
* intercepts an event bubbling up the widget hierarchy. The event intercepted
|
||||
* must be a "custom event", i.e. an event generated by the method 'trigger_up'.
|
||||
*
|
||||
* Note that this method really intercepts the event if @propagate is not set.
|
||||
* It will not be propagated further, and even the handlers on the target will
|
||||
* not fire.
|
||||
*
|
||||
* @param {Widget} widget the target widget (any Odoo widget)
|
||||
* @param {string} eventName description of the event
|
||||
* @param {function} fn callback executed when the even is intercepted
|
||||
* @param {boolean} [propagate=false]
|
||||
*/
|
||||
function intercept(widget, eventName, fn, propagate) {
|
||||
var _trigger_up = widget._trigger_up.bind(widget);
|
||||
widget._trigger_up = function (event) {
|
||||
if (event.name === eventName) {
|
||||
fn(event);
|
||||
if (!propagate) { return; }
|
||||
}
|
||||
_trigger_up(event);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the src attribute on images and iframes to prevent not found errors,
|
||||
* and optionally triggers an rpc with the src url as route on a widget.
|
||||
* This method is critical and must be fastest (=> no jQuery, no underscore)
|
||||
*
|
||||
* @param {HTMLElement} el
|
||||
* @param {[Widget]} widget the widget on which the rpc should be performed
|
||||
* @param {[function]} rpc
|
||||
*/
|
||||
function removeSrcAttribute(el, widget) {
|
||||
function removeSrcAttribute(el, rpc) {
|
||||
var nodes;
|
||||
el = el.nodeType === 8 ? el.nextSibling : el;
|
||||
if (el.nodeName === 'IMG' || el.nodeName === 'IFRAME') {
|
||||
nodes = [el];
|
||||
} else {
|
||||
@@ -68,14 +307,135 @@ function removeSrcAttribute(el, widget) {
|
||||
} else {
|
||||
node.setAttribute('src', 'about:blank');
|
||||
}
|
||||
if (widget) {
|
||||
widget._rpc({ route: src });
|
||||
if (rpc) {
|
||||
rpc(src, []);
|
||||
}
|
||||
$(node).trigger('load');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mock environment to test Owl Components. This function generates a test
|
||||
* env and sets it on the given Component. It also has several side effects,
|
||||
* like patching the global session or config objects. It returns a cleanup
|
||||
* function to call at the end of the test.
|
||||
*
|
||||
* @param {Component} Component
|
||||
* @param {Object} [params]
|
||||
* @param {Object} [params.actions]
|
||||
* @param {Object} [params.archs]
|
||||
* @param {string} [params.currentDate]
|
||||
* @param {Object} [params.data]
|
||||
* @param {boolean} [params.debug]
|
||||
* @param {function} [params.mockRPC]
|
||||
* @param {number} [params.fieldDebounce=0] the value of the DEBOUNCE attribute
|
||||
* of fields
|
||||
* @param {boolean} [params.debounce=true] if false, patch _.debounce to remove
|
||||
* its behavior
|
||||
* @param {boolean} [params.throttle=false] by default, _.throttle is patched to
|
||||
* remove its behavior, except if this params is set to true
|
||||
* @param {boolean} [params.mockSRC=false] if true, redirect src GET requests to
|
||||
* the mockServer
|
||||
* @param {MockServer} [mockServer]
|
||||
* @returns {Promise<function>} the cleanup function
|
||||
*/
|
||||
async function addMockEnvironmentOwl(Component, params, mockServer) {
|
||||
params = params || {};
|
||||
|
||||
// instantiate a mockServer if not provided
|
||||
if (!mockServer) {
|
||||
let Server = MockServer;
|
||||
if (params.mockRPC) {
|
||||
Server = MockServer.extend({ _performRpc: params.mockRPC });
|
||||
}
|
||||
mockServer = new Server(params.data, {
|
||||
actions: params.actions,
|
||||
archs: params.archs,
|
||||
currentDate: params.currentDate,
|
||||
debug: params.debug,
|
||||
});
|
||||
}
|
||||
|
||||
// make sure the debounce value for input fields is set to 0
|
||||
const initialDebounceValue = DebouncedField.prototype.DEBOUNCE;
|
||||
DebouncedField.prototype.DEBOUNCE = params.fieldDebounce || 0;
|
||||
const initialDOMDebounceValue = dom.DEBOUNCE;
|
||||
dom.DEBOUNCE = 0;
|
||||
|
||||
// patch underscore debounce/throttle functions
|
||||
const initialDebounce = _.debounce;
|
||||
if (params.debounce === false) {
|
||||
_.debounce = function (func) {
|
||||
return func;
|
||||
};
|
||||
}
|
||||
// fixme: throttle is inactive by default, should we make it explicit ?
|
||||
const initialThrottle = _.throttle;
|
||||
if (!('throttle' in params) || !params.throttle) {
|
||||
_.throttle = function (func) {
|
||||
return func;
|
||||
};
|
||||
}
|
||||
|
||||
// make sure images do not trigger a GET on the server
|
||||
$('body').on('DOMNodeInserted.removeSRC', function (ev) {
|
||||
let rpc;
|
||||
if (params.mockSRC) {
|
||||
rpc = mockServer.performRpc.bind(mockServer);
|
||||
}
|
||||
removeSrcAttribute(ev.target, rpc);
|
||||
});
|
||||
|
||||
// mock global objects for legacy widgets (session, config...)
|
||||
const restoreMockedGlobalObjects = _mockGlobalObjects(params);
|
||||
|
||||
// set the test env on owl Component
|
||||
const env = await _getMockedOwlEnv(params, mockServer);
|
||||
const originalEnv = Component.env;
|
||||
Component.env = makeTestEnvironment(env, mockServer.performRpc.bind(mockServer));
|
||||
|
||||
// while we have a mix between Owl and legacy stuff, some of them triggering
|
||||
// events on the env.bus (a new Bus instance especially created for the current
|
||||
// test), the others using core.bus, we have to ensure that events triggered
|
||||
// on env.bus are also triggered on core.bus (note that outside the testing
|
||||
// environment, both are the exact same instance of Bus)
|
||||
const envBusTrigger = env.bus.trigger;
|
||||
env.bus.trigger = function () {
|
||||
core.bus.trigger(...arguments);
|
||||
envBusTrigger.call(env.bus, ...arguments);
|
||||
};
|
||||
|
||||
// build the clean up function to call at the end of the test
|
||||
function cleanUp() {
|
||||
env.bus.destroy();
|
||||
Object.keys(env.services).forEach(function (s) {
|
||||
var service = env.services[s];
|
||||
if (service.destroy && !service.isDestroyed()) {
|
||||
service.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
DebouncedField.prototype.DEBOUNCE = initialDebounceValue;
|
||||
dom.DEBOUNCE = initialDOMDebounceValue;
|
||||
_.debounce = initialDebounce;
|
||||
_.throttle = initialThrottle;
|
||||
|
||||
// clear the caches (e.g. data_manager, ModelFieldSelector) at the end
|
||||
// of each test to avoid collisions
|
||||
core.bus.trigger('clear_cache');
|
||||
|
||||
$('body').off('DOMNodeInserted.removeSRC');
|
||||
$('.blockUI').remove(); // fixme: move to qunit_config in OdooAfterTestHook?
|
||||
|
||||
restoreMockedGlobalObjects();
|
||||
|
||||
Component.env = originalEnv;
|
||||
}
|
||||
|
||||
return cleanUp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mock environment to a widget. This helper function can simulate
|
||||
* various kind of side effects, such as mocking RPCs, changing the session,
|
||||
@@ -100,6 +460,7 @@ function removeSrcAttribute(el, widget) {
|
||||
* used to generate mock answers for every kind of routes supported by odoo
|
||||
* @param {number} [params.debug] if set to true, logs RPCs and uncaught Odoo
|
||||
* events.
|
||||
* @param {Object} [params.bus] the instance of Bus that will be used (in the env)
|
||||
* @param {function} [params.mockRPC] a function that will be used to override
|
||||
* the _performRpc method from the mock server. It is really useful to add
|
||||
* some custom rpc mocks, or to check some assertions.
|
||||
@@ -130,11 +491,7 @@ function removeSrcAttribute(el, widget) {
|
||||
* other methods on it.
|
||||
*/
|
||||
async function addMockEnvironment(widget, params) {
|
||||
var Server = MockServer;
|
||||
params.services = params.services || {};
|
||||
if (params.mockRPC) {
|
||||
Server = MockServer.extend({ _performRpc: params.mockRPC });
|
||||
}
|
||||
// log events triggered up if debug flag is true
|
||||
if (params.debug) {
|
||||
_observe(widget);
|
||||
var separator = window.location.href.indexOf('?') !== -1 ? "&" : "?";
|
||||
@@ -142,6 +499,11 @@ async function addMockEnvironment(widget, params) {
|
||||
console.log('%c[debug] debug mode activated', 'color: blue; font-weight: bold;', url);
|
||||
}
|
||||
|
||||
// instantiate mock server
|
||||
var Server = MockServer;
|
||||
if (params.mockRPC) {
|
||||
Server = MockServer.extend({ _performRpc: params.mockRPC });
|
||||
}
|
||||
var mockServer = new Server(params.data, {
|
||||
actions: params.actions,
|
||||
archs: params.archs,
|
||||
@@ -150,310 +512,60 @@ async function addMockEnvironment(widget, params) {
|
||||
widget: widget,
|
||||
});
|
||||
|
||||
// make sure images do not trigger a GET on the server
|
||||
$('body').on('DOMNodeInserted.removeSRC', function (event) {
|
||||
removeSrcAttribute(event.target, widget);
|
||||
});
|
||||
// build and set the Owl env on Component
|
||||
if (!('mockSRC' in params)) { // redirect src rpcs to the mock server
|
||||
params.mockSRC = true;
|
||||
}
|
||||
const cleanUp = await addMockEnvironmentOwl(owl.Component, params, mockServer);
|
||||
const env = owl.Component.env;
|
||||
|
||||
// make sure the debounce value for input fields is set to 0
|
||||
var initialDebounceValue = DebouncedField.prototype.DEBOUNCE;
|
||||
DebouncedField.prototype.DEBOUNCE = params.fieldDebounce || 0;
|
||||
var initialDOMDebounceValue = dom.DEBOUNCE;
|
||||
dom.DEBOUNCE = 0;
|
||||
var initialSession, initialConfig, initialParameters, initialDebounce, initialThrottle;
|
||||
initialSession = _.extend({}, session);
|
||||
session.getTZOffset = function () {
|
||||
return 0; // by default, but may be overridden in specific tests
|
||||
};
|
||||
if ('session' in params) {
|
||||
_.extend(session, params.session);
|
||||
}
|
||||
if ('config' in params) {
|
||||
initialConfig = _.clone(config);
|
||||
initialConfig.device = _.clone(config.device);
|
||||
if ('device' in params.config) {
|
||||
_.extend(config.device, params.config.device);
|
||||
}
|
||||
if ('debug' in params.config) {
|
||||
odoo.debug = params.config.debug;
|
||||
}
|
||||
}
|
||||
if ('translateParameters' in params) {
|
||||
initialParameters = _.extend({}, core._t.database.parameters);
|
||||
_.extend(core._t.database.parameters, params.translateParameters);
|
||||
}
|
||||
if (params.debounce === false) {
|
||||
initialDebounce = _.debounce;
|
||||
_.debounce = function (func) {
|
||||
return func;
|
||||
};
|
||||
}
|
||||
if (!('throttle' in params) || !params.throttle) {
|
||||
initialThrottle = _.throttle;
|
||||
_.throttle = function (func) {
|
||||
return func;
|
||||
};
|
||||
}
|
||||
|
||||
var widgetDestroy = widget.destroy;
|
||||
// ensure to clean up everything when the widget will be destroyed
|
||||
const destroy = widget.destroy;
|
||||
widget.destroy = function () {
|
||||
// clear the caches (e.g. data_manager, ModelFieldSelector) when the
|
||||
// widget is destroyed, at the end of each test to avoid collisions
|
||||
core.bus.trigger('clear_cache');
|
||||
|
||||
Object.keys(services).forEach(function(s) {
|
||||
var service = services[s];
|
||||
if (service && !service.isDestroyed())
|
||||
service.destroy();
|
||||
});
|
||||
|
||||
DebouncedField.prototype.DEBOUNCE = initialDebounceValue;
|
||||
dom.DEBOUNCE = initialDOMDebounceValue;
|
||||
if (params.debounce === false) {
|
||||
_.debounce = initialDebounce;
|
||||
}
|
||||
if (!('throttle' in params) || !params.throttle) {
|
||||
_.throttle = initialThrottle;
|
||||
}
|
||||
|
||||
var key;
|
||||
if ('session' in params) {
|
||||
for (key in session) {
|
||||
delete session[key];
|
||||
}
|
||||
}
|
||||
_.extend(session, initialSession);
|
||||
if ('config' in params) {
|
||||
for (key in config) {
|
||||
delete config[key];
|
||||
}
|
||||
_.extend(config, initialConfig);
|
||||
}
|
||||
if ('translateParameters' in params) {
|
||||
for (key in core._t.database.parameters) {
|
||||
delete core._t.database.parameters[key];
|
||||
}
|
||||
_.extend(core._t.database.parameters, initialParameters);
|
||||
}
|
||||
|
||||
$('body').off('DOMNodeInserted.removeSRC');
|
||||
$('body').removeClass('debug');
|
||||
$('.blockUI').remove();
|
||||
|
||||
widgetDestroy.call(this);
|
||||
cleanUp();
|
||||
destroy.call(this, ...arguments);
|
||||
};
|
||||
|
||||
// Dispatch service calls
|
||||
// Note: some services could call other services at init,
|
||||
// Which is why we have to init services after that
|
||||
var services = {};
|
||||
// intercept service/data manager calls and redirect them to the env
|
||||
intercept(widget, 'call_service', function (ev) {
|
||||
var args, result;
|
||||
if (services[ev.data.service]) {
|
||||
var service = services[ev.data.service];
|
||||
args = (ev.data.args || []);
|
||||
result = service[ev.data.method].apply(service, args);
|
||||
} else if (ev.data.service === 'ajax' && ev.data.method === 'rpc') {
|
||||
// use ajax service that is mocked by the server
|
||||
var route = ev.data.args[0];
|
||||
args = ev.data.args[1];
|
||||
result = mockServer.performRpc(route, args);
|
||||
if (env.services[ev.data.service]) {
|
||||
var service = env.services[ev.data.service];
|
||||
const result = service[ev.data.method].apply(service, ev.data.args || []);
|
||||
ev.data.callback(result);
|
||||
}
|
||||
ev.data.callback(result);
|
||||
});
|
||||
|
||||
intercept(widget, 'load_action', function (event) {
|
||||
mockServer.performRpc('/web/action/load', {
|
||||
action_id: event.data.actionID,
|
||||
additional_context: event.data.context,
|
||||
}).then(function (action) {
|
||||
event.data.on_success(action);
|
||||
});
|
||||
intercept(widget, 'load_action', async ev => {
|
||||
const action = await env.dataManager.load_action(ev.data.actionID, ev.data.context);
|
||||
ev.data.on_success(action);
|
||||
});
|
||||
|
||||
intercept(widget, "load_views", function (event) {
|
||||
mockServer.performRpc('/web/dataset/call_kw/' + event.data.modelName, {
|
||||
args: [],
|
||||
kwargs: {
|
||||
context: event.data.context,
|
||||
options: event.data.options,
|
||||
views: event.data.views,
|
||||
},
|
||||
method: 'load_views',
|
||||
model: event.data.modelName,
|
||||
}).then(function (views) {
|
||||
views = _.mapObject(views, function (viewParams) {
|
||||
return fieldsViewGet(mockServer, viewParams);
|
||||
});
|
||||
if ('search' in views && params.favoriteFilters) {
|
||||
views.search.favoriteFilters = params.favoriteFilters;
|
||||
}
|
||||
event.data.on_success(views);
|
||||
});
|
||||
});
|
||||
|
||||
intercept(widget, "get_session", function (event) {
|
||||
event.data.callback(session);
|
||||
});
|
||||
|
||||
intercept(widget, "load_filters", function (event) {
|
||||
if (params.debug) {
|
||||
console.log('[mock] load_filters', event.data);
|
||||
intercept(widget, "load_views", async ev => {
|
||||
const params = {
|
||||
model: ev.data.modelName,
|
||||
context: ev.data.context,
|
||||
views_descr: ev.data.views,
|
||||
};
|
||||
const views = await env.dataManager.load_views(params, ev.data.options);
|
||||
if ('search' in views && params.favoriteFilters) {
|
||||
views.search.favoriteFilters = params.favoriteFilters;
|
||||
}
|
||||
event.data.on_success([]);
|
||||
ev.data.on_success(views);
|
||||
});
|
||||
intercept(widget, "get_session", ev => {
|
||||
ev.data.callback(session);
|
||||
});
|
||||
intercept(widget, "load_filters", async ev => {
|
||||
const filters = await env.dataManager.load_filters(ev.data);
|
||||
ev.data.on_success(filters);
|
||||
});
|
||||
|
||||
// make sure all Odoo events bubbling up are intercepted
|
||||
if ('intercepts' in params) {
|
||||
_.each(params.intercepts, function (cb, name) {
|
||||
intercept(widget, name, cb);
|
||||
});
|
||||
}
|
||||
|
||||
// Deploy services
|
||||
var done = false;
|
||||
var servicesToDeploy = _.clone(params.services);
|
||||
if (!servicesToDeploy.ajax) {
|
||||
services.ajax = null; // use mocked ajax from mocked server
|
||||
}
|
||||
while (!done) {
|
||||
var serviceName = _.findKey(servicesToDeploy, function (Service) {
|
||||
return !_.some(Service.prototype.dependencies, function (depName) {
|
||||
return !_.has(services, depName);
|
||||
});
|
||||
});
|
||||
if (serviceName) {
|
||||
var Service = servicesToDeploy[serviceName];
|
||||
var service = services[serviceName] = new Service(widget);
|
||||
delete servicesToDeploy[serviceName];
|
||||
|
||||
intercept(service, "get_session", function (event) {
|
||||
event.data.callback(session);
|
||||
});
|
||||
service.start();
|
||||
} else {
|
||||
var serviceNames = _.keys(servicesToDeploy);
|
||||
if (serviceNames.length) {
|
||||
console.warn("Non loaded services:", serviceNames);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for asynchronous services to properly start
|
||||
await new Promise(setTimeout);
|
||||
// make sure all other Odoo events bubbling up are intercepted
|
||||
Object.keys(params.intercepts || {}).forEach(function (name) {
|
||||
intercept(widget, name, params.intercepts[name]);
|
||||
});
|
||||
|
||||
return mockServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* performs a fields_view_get, and mocks the postprocessing done by the
|
||||
* data_manager to return an equivalent structure.
|
||||
*
|
||||
* @param {MockServer} server
|
||||
* @param {Object} params
|
||||
* @param {string} params.model
|
||||
* @returns {Object} an object with 3 keys: arch, fields and viewFields
|
||||
*/
|
||||
function fieldsViewGet(server, params) {
|
||||
var fieldsView = server.fieldsViewGet(params);
|
||||
// mock the structure produced by the DataManager
|
||||
fieldsView.viewFields = fieldsView.fields;
|
||||
fieldsView.fields = server.fieldsGet(params.model);
|
||||
return fieldsView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mocked environment to be used by OWL components in tests.
|
||||
*
|
||||
* @param {Object} [params]
|
||||
* @param {Object} [params.actions] the actions given to the mock server
|
||||
* @param {Object} [params.archs] this archs given to the mock server
|
||||
* @param {Object} [params.data] the business data given to the mock server
|
||||
* @param {boolean} [params.debug]
|
||||
* @param {Object} [params.env]
|
||||
* @param {function} [params.mockRPC]
|
||||
* @param {function} [params.server] an already instantiated server to avoid
|
||||
* creating another one.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function getMockedOwlEnv(params = {}) {
|
||||
let server;
|
||||
if (params.server) {
|
||||
server = params.server;
|
||||
} else {
|
||||
let Server = MockServer;
|
||||
if (params.mockRPC) {
|
||||
Server = MockServer.extend({ _performRpc: params.mockRPC });
|
||||
}
|
||||
server = new Server(params.data, {
|
||||
actions: params.actions,
|
||||
archs: params.archs,
|
||||
debug: params.debug,
|
||||
});
|
||||
}
|
||||
const env = Object.assign({
|
||||
dataManager: {
|
||||
load_action: (actionID, context) => {
|
||||
return server.performRpc('/web/action/load', {
|
||||
kwargs: {
|
||||
action_id: actionID,
|
||||
additional_context: context,
|
||||
},
|
||||
});
|
||||
},
|
||||
load_views: (params, options) => {
|
||||
return server.performRpc('/web/dataset/call_kw/' + params.model, {
|
||||
args: [],
|
||||
kwargs: {
|
||||
context: params.context,
|
||||
options: options,
|
||||
views: params.views_descr,
|
||||
},
|
||||
method: 'load_views',
|
||||
model: params.model,
|
||||
}).then(function (views) {
|
||||
return _.mapObject(views, viewParams => {
|
||||
return fieldsViewGet(server, viewParams);
|
||||
});
|
||||
});
|
||||
},
|
||||
load_filters: params => {
|
||||
if (params.debug) {
|
||||
console.log('[mock] load_filters', params);
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
},
|
||||
session: params.session || {},
|
||||
}, params.env);
|
||||
return makeTestEnvironment(env, server.performRpc.bind(server));
|
||||
}
|
||||
|
||||
/**
|
||||
* intercepts an event bubbling up the widget hierarchy. The event intercepted
|
||||
* must be a "custom event", i.e. an event generated by the method 'trigger_up'.
|
||||
*
|
||||
* Note that this method really intercepts the event if @propagate is not set.
|
||||
* It will not be propagated further, and even the handlers on the target will
|
||||
* not fire.
|
||||
*
|
||||
* @param {Widget} widget the target widget (any Odoo widget)
|
||||
* @param {string} eventName description of the event
|
||||
* @param {function} fn callback executed when the even is intercepted
|
||||
* @param {boolean} [propagate=false]
|
||||
*/
|
||||
function intercept(widget, eventName, fn, propagate) {
|
||||
var _trigger_up = widget._trigger_up.bind(widget);
|
||||
widget._trigger_up = function (event) {
|
||||
if (event.name === eventName) {
|
||||
fn(event);
|
||||
if (!propagate) { return; }
|
||||
}
|
||||
_trigger_up(event);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch window.Date so that the time starts its flow from the provided Date.
|
||||
*
|
||||
@@ -644,7 +756,7 @@ function patchSetTimeout() {
|
||||
return {
|
||||
addMockEnvironment: addMockEnvironment,
|
||||
fieldsViewGet: fieldsViewGet,
|
||||
getMockedOwlEnv: getMockedOwlEnv,
|
||||
addMockEnvironmentOwl: addMockEnvironmentOwl,
|
||||
intercept: intercept,
|
||||
patchDate: patchDate,
|
||||
patch: patch,
|
||||
|
||||
@@ -5,9 +5,9 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
const testUtils = require('web.test_utils');
|
||||
const Widget = require('web.Widget');
|
||||
|
||||
const getMockedOwlEnv = testUtils.mock.getMockedOwlEnv;
|
||||
const makeTestPromise = testUtils.makeTestPromise;
|
||||
const nextTick = testUtils.nextTick;
|
||||
const addMockEnvironmentOwl = testUtils.mock.addMockEnvironmentOwl;
|
||||
|
||||
const { Component, tags, useState } = owl;
|
||||
const { xml } = tags;
|
||||
@@ -448,17 +448,17 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
this.MyWidget = MyWidget;
|
||||
}
|
||||
}
|
||||
Parent.env = getMockedOwlEnv({
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(`${route} ${args.val}`);
|
||||
return Promise.resolve();
|
||||
},
|
||||
});
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<ComponentAdapter Component="MyWidget"/>
|
||||
</div>`;
|
||||
Parent.components = { ComponentAdapter };
|
||||
const cleanUp = await addMockEnvironmentOwl(Parent, {
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(`${route} ${args.val}`);
|
||||
return Promise.resolve();
|
||||
},
|
||||
});
|
||||
|
||||
const target = testUtils.prepareTarget();
|
||||
const parent = new Parent();
|
||||
@@ -468,6 +468,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
assert.verifySteps(['some/route 2']);
|
||||
|
||||
parent.destroy();
|
||||
cleanUp();
|
||||
});
|
||||
|
||||
QUnit.test("sub widget that calls a service", async function (assert) {
|
||||
@@ -493,16 +494,14 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
this.MyWidget = MyWidget;
|
||||
}
|
||||
}
|
||||
const env = getMockedOwlEnv();
|
||||
env.services.math = {
|
||||
sqrt: v => Math.sqrt(v),
|
||||
};
|
||||
Parent.env = env;
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<ComponentAdapter Component="MyWidget"/>
|
||||
</div>`;
|
||||
Parent.components = { ComponentAdapter };
|
||||
Parent.env.services.math = {
|
||||
sqrt: v => Math.sqrt(v),
|
||||
};
|
||||
|
||||
const target = testUtils.prepareTarget();
|
||||
const parent = new Parent();
|
||||
@@ -525,20 +524,21 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
this.MyWidget = MyWidget;
|
||||
}
|
||||
}
|
||||
Parent.env = getMockedOwlEnv({
|
||||
session: { key: 'value' },
|
||||
});
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<ComponentAdapter Component="MyWidget"/>
|
||||
</div>`;
|
||||
Parent.components = { ComponentAdapter };
|
||||
const cleanUp = await addMockEnvironmentOwl(Parent, {
|
||||
session: { key: 'value' },
|
||||
});
|
||||
|
||||
const target = testUtils.prepareTarget();
|
||||
const parent = new Parent();
|
||||
await parent.mount(target);
|
||||
|
||||
parent.destroy();
|
||||
cleanUp();
|
||||
});
|
||||
|
||||
QUnit.test("sub widget that calls load_views", async function (assert) {
|
||||
@@ -555,7 +555,12 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
this.MyWidget = MyWidget;
|
||||
}
|
||||
}
|
||||
Parent.env = getMockedOwlEnv({
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<ComponentAdapter Component="MyWidget"/>
|
||||
</div>`;
|
||||
Parent.components = { ComponentAdapter };
|
||||
const cleanUp = await addMockEnvironmentOwl(Parent, {
|
||||
mockRPC: function (route, args) {
|
||||
assert.strictEqual(route, '/web/dataset/call_kw/some_model');
|
||||
assert.deepEqual(args.kwargs.context, { x: 2 });
|
||||
@@ -563,11 +568,6 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
});
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<ComponentAdapter Component="MyWidget"/>
|
||||
</div>`;
|
||||
Parent.components = { ComponentAdapter };
|
||||
|
||||
const target = testUtils.prepareTarget();
|
||||
const parent = new Parent();
|
||||
@@ -576,6 +576,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
assert.strictEqual(parent.el.innerHTML, '<div></div>');
|
||||
|
||||
parent.destroy();
|
||||
cleanUp();
|
||||
});
|
||||
|
||||
QUnit.test("sub widgets in a t-if/t-else", async function (assert) {
|
||||
|
||||
@@ -11,7 +11,7 @@ QUnit.module('DebugManager', {}, function () {
|
||||
QUnit.test("list: edit view menu item", async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var debugManager = createDebugManager();
|
||||
var debugManager = await createDebugManager();
|
||||
|
||||
await debugManager.appendTo($('#qunit-fixture'));
|
||||
|
||||
@@ -43,7 +43,7 @@ QUnit.module('DebugManager', {}, function () {
|
||||
QUnit.test("form: Manage Attachments option", async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var debugManager = createDebugManager({
|
||||
var debugManager = await createDebugManager({
|
||||
intercepts: {
|
||||
do_action: function (event) {
|
||||
assert.deepEqual(event.data.action, {
|
||||
@@ -126,7 +126,7 @@ QUnit.module('DebugManager', {}, function () {
|
||||
});
|
||||
|
||||
// Now the real tested component
|
||||
var debugManager = createDebugManager({
|
||||
var debugManager = await createDebugManager({
|
||||
data: data,
|
||||
mockRPC: function (route, args) {
|
||||
if (route == "/web/dataset/call_kw/ir.default/set") {
|
||||
|
||||
@@ -136,7 +136,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = ['foo'];
|
||||
this.params.context = { active_field: 2 };
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -171,7 +171,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.res_id = 99;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -190,7 +190,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['foo', 'qux'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -211,7 +211,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.data.partner.records[1].qux = 1;
|
||||
|
||||
this.params.fieldNames = ['qux'];
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -238,7 +238,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
var rpcCount = 0;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -277,7 +277,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = ['foo', 'bar'];
|
||||
this.params.context = { hello: 'world' };
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -317,7 +317,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
var rpcCount = 0;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -354,7 +354,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['foo'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -381,7 +381,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.data.partner.records[1].product_ids = [37];
|
||||
this.params.fieldNames = ['product_ids'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -461,7 +461,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['product_id'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -495,7 +495,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['foo', 'product_id'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -524,7 +524,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = ['foo', 'product_id'];
|
||||
this.params.res_id = 1;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -553,7 +553,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
},
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -583,7 +583,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
},
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -615,7 +615,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
},
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -641,7 +641,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.context = { active_field: 2 };
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -671,7 +671,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.groupedBy = [];
|
||||
this.params.res_id = undefined;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -698,7 +698,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.type = 'record';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -732,7 +732,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.type = 'record';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -784,7 +784,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
};
|
||||
this.params.viewType = 'form';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -822,7 +822,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.type = 'record';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -848,7 +848,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
fields.product_id.default = 37;
|
||||
fields.other_product_id.default = 41;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -880,7 +880,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['foo'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -902,7 +902,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = ['category'];
|
||||
this.params.res_id = 1;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -927,7 +927,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['foo'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -951,7 +951,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = ['product_id'];
|
||||
|
||||
var self = this;
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -981,7 +981,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
|
||||
var filterEnabled = false;
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1046,7 +1046,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.groupedBy = ['date:month'];
|
||||
this.params.res_id = undefined;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1072,7 +1072,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
};
|
||||
this.data.partner.records[0].selection = 'a';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1108,7 +1108,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.context = { active_field: 2 };
|
||||
|
||||
var id;
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1146,7 +1146,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.params.fieldNames = ['product_ids'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1183,7 +1183,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
QUnit.test('create commands on a one2many', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1260,7 +1260,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
type: 'record',
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1297,7 +1297,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
QUnit.test('dates are properly loaded and parsed (record)', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1328,7 +1328,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
QUnit.test('dates are properly loaded and parsed (list)', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1355,7 +1355,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
QUnit.test('dates are properly loaded and parsed (default_get)', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1379,7 +1379,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.data.partner.fields.category.default = [12, 14];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1412,7 +1412,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
};
|
||||
this.data.partner.fields.category.type = 'many2one';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1464,7 +1464,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
string: "O2M", type: 'one2many', relation: 'partner', default: [[6, 0, [1]]],
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1510,7 +1510,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.data.partner.fields.product_id.context = "{'hello': 'world', 'test': foo}";
|
||||
this.data.partner.fields.product_id.domain = "[['hello', 'like', 'world'], ['test', 'like', foo]]";
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1538,7 +1538,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
model.destroy();
|
||||
|
||||
// Try again with xml override of field domain and context
|
||||
model = createModel({
|
||||
model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1585,7 +1585,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
}
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1650,7 +1650,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
}
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1699,7 +1699,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
QUnit.test('default_get with one2many values', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1738,7 +1738,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
assert.expect(3);
|
||||
var rpcCount = 0;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1773,7 +1773,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
assert.expect(5);
|
||||
var rpcCount = 0;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1812,7 +1812,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
assert.expect(5);
|
||||
var rpcCount = 0;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1857,7 +1857,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
assert.expect(4);
|
||||
var rpcCount = 0;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1888,7 +1888,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
assert.expect(2);
|
||||
let rpcCount = 0;
|
||||
|
||||
const model = createModel({
|
||||
const model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1916,7 +1916,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
this.data.partner.fields.product_id.context = "{'id': id, 'active_id': active_id, 'active_ids': active_ids, 'active_model': active_model}";
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -1949,7 +1949,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = ['category'];
|
||||
this.params.res_id = 1;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -1991,7 +1991,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
viewType: 'form',
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2011,7 +2011,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
assert.expect(2);
|
||||
|
||||
this.data.partner.fields.foo.default = 'default';
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2042,7 +2042,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.fieldNames = Object.keys(this.data.partner.fields);
|
||||
this.params.res_id = 1;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2095,7 +2095,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.viewType = 'form';
|
||||
this.params.res_id = 1;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2133,7 +2133,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.groupedBy = [];
|
||||
this.params.res_id = undefined;
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -2164,7 +2164,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.type = 'record';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -2196,7 +2196,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.type = 'record';
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2215,7 +2215,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = undefined;
|
||||
this.params.orderedBy = [{ name: 'display_name', asc: true }];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route) {
|
||||
@@ -2269,7 +2269,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.params.res_id = 1;
|
||||
this.params.fieldNames = ['foobool', 'foobool2'];
|
||||
this.params.fields = this.data.partner.fields;
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2291,7 +2291,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.data.partner.records[1].product_ids = [37, 38];
|
||||
this.params.fieldNames = ['product_ids'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2341,7 +2341,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
this.data.partner.records[1].product_ids = [37, 38];
|
||||
this.params.fieldNames = ['product_ids'];
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2401,7 +2401,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
},
|
||||
};
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
@@ -2448,7 +2448,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
|
||||
QUnit.test('identify correct active field', async function(assert) {
|
||||
assert.expect(4);
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
@@ -2541,7 +2541,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.expect(2);
|
||||
|
||||
var instanceNumber = 0;
|
||||
testUtils.mock.patch(mixins.ParentedMixin, {
|
||||
@@ -2579,21 +2579,10 @@ QUnit.module('Views', {
|
||||
};
|
||||
|
||||
var calendar = await createCalendarView(params);
|
||||
calendar.destroy();
|
||||
|
||||
var initialInstanceNumber = instanceNumber;
|
||||
instanceNumber = 0;
|
||||
|
||||
calendar = await createCalendarView(params);
|
||||
|
||||
// call destroy function of controller to ensure that it correctly destroys everything
|
||||
calendar.__destroy();
|
||||
|
||||
// + 1 (parent)
|
||||
assert.strictEqual(instanceNumber, initialInstanceNumber + 1,
|
||||
"every widget must be destroyed exept the parent");
|
||||
assert.ok(instanceNumber > 0);
|
||||
|
||||
calendar.destroy();
|
||||
assert.strictEqual(instanceNumber, 0);
|
||||
|
||||
testUtils.mock.unpatch(mixins.ParentedMixin);
|
||||
});
|
||||
|
||||
@@ -7706,7 +7706,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.expect(2);
|
||||
|
||||
var instanceNumber = 0;
|
||||
await testUtils.mock.patch(mixins.ParentedMixin, {
|
||||
@@ -7766,21 +7766,10 @@ QUnit.module('Views', {
|
||||
};
|
||||
|
||||
var form = await createView(params);
|
||||
form.destroy();
|
||||
|
||||
var initialInstanceNumber = instanceNumber;
|
||||
instanceNumber = 0;
|
||||
|
||||
form = await createView(params);
|
||||
|
||||
// call destroy function of controller to ensure that it correctly destroys everything
|
||||
form.__destroy();
|
||||
|
||||
// + 4 (parent)
|
||||
assert.strictEqual(instanceNumber, initialInstanceNumber + 1,
|
||||
"every widget must be destroyed exept the parent");
|
||||
assert.ok(instanceNumber > 0);
|
||||
|
||||
form.destroy();
|
||||
assert.strictEqual(instanceNumber, 0);
|
||||
|
||||
await testUtils.mock.unpatch(mixins.ParentedMixin);
|
||||
});
|
||||
|
||||
@@ -67,7 +67,7 @@ QUnit.module('Views', {
|
||||
assert.expect(22);
|
||||
|
||||
var calledRoutes = {};
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: KanbanModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route) {
|
||||
@@ -132,7 +132,7 @@ QUnit.module('Views', {
|
||||
var done = assert.async();
|
||||
assert.expect(4);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: KanbanModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -173,7 +173,7 @@ QUnit.module('Views', {
|
||||
var done = assert.async();
|
||||
assert.expect(2);
|
||||
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: KanbanModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -210,7 +210,7 @@ QUnit.module('Views', {
|
||||
this.data.partner.records.push({id: 3, foo: 'aaa', product_id: 37});
|
||||
|
||||
var nbReseq = 0;
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: KanbanModel,
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
@@ -270,7 +270,7 @@ QUnit.module('Views', {
|
||||
assert.expect(8);
|
||||
|
||||
var self = this;
|
||||
var model = createModel({
|
||||
var model = await createModel({
|
||||
Model: KanbanModel,
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
@@ -5420,7 +5420,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.expect(2);
|
||||
|
||||
var instanceNumber = 0;
|
||||
testUtils.mock.patch(mixins.ParentedMixin, {
|
||||
@@ -5457,21 +5457,10 @@ QUnit.module('Views', {
|
||||
};
|
||||
|
||||
var kanban = await createView(params);
|
||||
kanban.destroy();
|
||||
|
||||
var initialInstanceNumber = instanceNumber;
|
||||
instanceNumber = 0;
|
||||
|
||||
kanban = await createView(params);
|
||||
|
||||
// call destroy function of controller to ensure that it correctly destroys everything
|
||||
kanban.__destroy();
|
||||
|
||||
// + 1 (parent)
|
||||
assert.strictEqual(instanceNumber, initialInstanceNumber + 1,
|
||||
"every widget must be destroyed exept the parent");
|
||||
assert.ok(instanceNumber > 0);
|
||||
|
||||
kanban.destroy();
|
||||
assert.strictEqual(instanceNumber, 0);
|
||||
|
||||
testUtils.mock.unpatch(mixins.ParentedMixin);
|
||||
});
|
||||
|
||||
@@ -7409,7 +7409,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.expect(2);
|
||||
|
||||
var instanceNumber = 0;
|
||||
testUtils.mock.patch(mixins.ParentedMixin, {
|
||||
@@ -7446,21 +7446,10 @@ QUnit.module('Views', {
|
||||
};
|
||||
|
||||
var list = await createView(params);
|
||||
list.destroy();
|
||||
|
||||
var initialInstanceNumber = instanceNumber;
|
||||
instanceNumber = 0;
|
||||
|
||||
list = await createView(params);
|
||||
|
||||
// call destroy function of controller to ensure that it correctly destroys everything
|
||||
list.__destroy();
|
||||
|
||||
// + 1 (parent)
|
||||
assert.strictEqual(instanceNumber, initialInstanceNumber + 1,
|
||||
"every widget must be destroyed exept the parent");
|
||||
assert.ok(instanceNumber > 0);
|
||||
|
||||
list.destroy();
|
||||
assert.strictEqual(instanceNumber, 0);
|
||||
|
||||
testUtils.mock.unpatch(mixins.ParentedMixin);
|
||||
});
|
||||
|
||||
@@ -12,8 +12,7 @@ var createView = testUtils.createView;
|
||||
|
||||
async function createParent(params) {
|
||||
var widget = new Widget();
|
||||
params.server = await testUtils.mock.addMockEnvironment(widget, params);
|
||||
owl.Component.env = testUtils.mock.getMockedOwlEnv(params);
|
||||
params.server = await testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ async function createSwitchCompanyMenu(params) {
|
||||
params = params || {};
|
||||
var target = params.debug ? document.body : $('#qunit-fixture');
|
||||
var menu = new SwitchCompanyMenu();
|
||||
testUtils.mock.addMockEnvironment(menu, params);
|
||||
await testUtils.mock.addMockEnvironment(menu, params);
|
||||
await menu.appendTo(target)
|
||||
return menu
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ QUnit.module('DomainSelector', {
|
||||
readonly: false,
|
||||
debugMode: true,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await domainSelector.appendTo($target);
|
||||
|
||||
// As we gave an empty domain, there should be a visible button to add
|
||||
@@ -161,7 +161,7 @@ QUnit.module('DomainSelector', {
|
||||
var domainSelector = new DomainSelector(null, "partner", [["nice_datetime", "=", "2017-03-27 15:42:00"]], {
|
||||
readonly: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await domainSelector.appendTo($target);
|
||||
|
||||
// Check that there is a datepicker to choose the date
|
||||
@@ -189,7 +189,7 @@ QUnit.module('DomainSelector', {
|
||||
debugMode: true,
|
||||
readonly: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await domainSelector.appendTo($target);
|
||||
|
||||
await testUtils.fields.editAndTrigger(domainSelector.$('.o_domain_leaf_value_input'),
|
||||
@@ -210,7 +210,7 @@ QUnit.module('DomainSelector', {
|
||||
debugMode: true,
|
||||
readonly: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await domainSelector.appendTo($target);
|
||||
|
||||
assert.strictEqual(domainSelector.$el.text(), "This domain is not supported.",
|
||||
@@ -230,7 +230,7 @@ QUnit.module('DomainSelector', {
|
||||
debugMode: true,
|
||||
default: [["foo","=","kikou"]],
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
|
||||
await domainSelector.appendTo($target);
|
||||
|
||||
// Clicking on the button should add a visible field selector in the
|
||||
|
||||
@@ -59,7 +59,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
readonly: false,
|
||||
debugMode: true,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await fieldSelector.appendTo($target);
|
||||
var $value = fieldSelector.$("> .o_field_selector_value");
|
||||
|
||||
@@ -182,7 +182,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
readonly: false,
|
||||
debugMode: true,
|
||||
});
|
||||
testUtils.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await testUtils.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await fieldSelector.appendTo($target);
|
||||
|
||||
// Focusing the field selector input should open a field selector popover
|
||||
@@ -215,7 +215,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
return field.type === 'many2one';
|
||||
},
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await fieldSelector.appendTo($target);
|
||||
|
||||
fieldSelector.$el.trigger('focusin');
|
||||
@@ -237,7 +237,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
var fieldSelector = new ModelFieldSelector(null, "partner", [], {
|
||||
readonly: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await fieldSelector.appendTo($target);
|
||||
|
||||
fieldSelector.$el.trigger('focusin');
|
||||
@@ -269,7 +269,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
readonly: false,
|
||||
showSearchInput: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(fieldSelector, { data: this.data });
|
||||
await testUtils.mock.addMockEnvironment(fieldSelector, { data: this.data });
|
||||
await fieldSelector.appendTo($target);
|
||||
|
||||
fieldSelector.$el.trigger('focusin');
|
||||
@@ -291,7 +291,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
readonly: false,
|
||||
showSearchInput: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await fieldSelector.appendTo($target);
|
||||
|
||||
var $fieldName = fieldSelector.$('.o_field_selector_chain_part');
|
||||
@@ -311,7 +311,7 @@ QUnit.module('ModelFieldSelector', {
|
||||
readonly: false,
|
||||
showSearchInput: false,
|
||||
});
|
||||
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
|
||||
await fieldSelector.appendTo($target);
|
||||
|
||||
var $fieldName = fieldSelector.$('.o_field_selector_chain_part');
|
||||
|
||||
@@ -167,6 +167,8 @@
|
||||
|
||||
<script type="text/javascript" src="/web/static/src/js/tools/debug_manager.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/src/js/common_env.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/src/js/widgets/name_and_signature.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/widgets/notification.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/widgets/rainbow_man.js"></script>
|
||||
|
||||
@@ -293,12 +293,12 @@ function wysiwygData(data) {
|
||||
*
|
||||
* @param {object} params
|
||||
*/
|
||||
function createWysiwyg(params) {
|
||||
async function createWysiwyg(params) {
|
||||
patch();
|
||||
params.data = wysiwygData(params.data);
|
||||
|
||||
var parent = new Widget();
|
||||
testUtils.mock.addMockEnvironment(parent, params);
|
||||
await testUtils.mock.addMockEnvironment(parent, params);
|
||||
|
||||
var wysiwygOptions = _.extend({}, params.wysiwygOptions, {
|
||||
recordInfo: {
|
||||
|
||||
@@ -20,7 +20,7 @@ odoo.define('web_tour.tour_manager_tests', async function (require) {
|
||||
* @param {Object[]} params.tours { {string} name, {Object} option, {Object[]} steps }
|
||||
*/
|
||||
async function createTourManager({ consumed_tours, debug, template, tours }) {
|
||||
const parent = testUtils.createParent({ debug });
|
||||
const parent = await testUtils.createParent({ debug });
|
||||
const tourManager = new TourManager(parent, consumed_tours);
|
||||
tourManager.running_step_delay = 0;
|
||||
for (const { name, options, steps } of tours) {
|
||||
|
||||
Reference in New Issue
Block a user