[FIX] mail, bus: fix mock sendone/many crash during tests
The mock of sendone/many was relying on the bus_service. Since owl.Component.env is changing during tests setup, the bus_service was not always defined. In order to make this more reliable, the longpolling/poll route is now mocked, returning a promise that can be resolved by the sendone/many methods. closes odoo/odoo#97298 Related: odoo/enterprise#30059 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { MockServer } from "@web/../tests/helpers/mock_server";
|
||||
import { makeDeferred } from "@web/../tests/helpers/utils";
|
||||
|
||||
patch(MockServer.prototype, 'bus', {
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.pendingLongpollingPromise = null;
|
||||
this.notificationsToBeResolved = [];
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async _performRPC(route, args) {
|
||||
if (route === '/longpolling/poll') {
|
||||
const longpollingPromise = makeDeferred();
|
||||
if (this.notificationsToBeResolved.length) {
|
||||
longpollingPromise.resolve(this.notificationsToBeResolved);
|
||||
this.notificationsToBeResolved = [];
|
||||
} else {
|
||||
this.pendingLongpollingPromise = longpollingPromise;
|
||||
}
|
||||
return longpollingPromise;
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
/**
|
||||
* Simulates `_sendone` on `bus.bus`.
|
||||
*
|
||||
* @param {string} channel
|
||||
* @param {string} notificationType
|
||||
* @param {any} message
|
||||
*/
|
||||
_mockBusBus__sendone(channel, notificationType, message) {
|
||||
this._mockBusBus__sendmany([[channel, notificationType, message]]);
|
||||
},
|
||||
/**
|
||||
* Simulates `_sendmany` on `bus.bus`.
|
||||
*
|
||||
* @param {Array} notifications
|
||||
*/
|
||||
_mockBusBus__sendmany(notifications) {
|
||||
const values = [];
|
||||
for (const notification of notifications) {
|
||||
const [type, payload] = notification.slice(1, notification.length);
|
||||
values.push({ message: { payload, type } });
|
||||
}
|
||||
if (this.pendingLongpollingPromise) {
|
||||
this.pendingLongpollingPromise.resolve(values);
|
||||
this.pendingLongpollingPromise = null;
|
||||
} else {
|
||||
this.notificationsToBeResolved.push(...values);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -578,29 +578,6 @@ patch(MockServer.prototype, 'mail', {
|
||||
// Private Mocked Methods
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Simulates `_sendone` on `bus.bus`.
|
||||
*
|
||||
* @param {string} channel
|
||||
* @param {string} notificationType
|
||||
* @param {any} message
|
||||
*/
|
||||
_mockBusBus__sendone(channel, notificationType, message) {
|
||||
this._mockBusBus__sendmany([[channel, notificationType, message]]);
|
||||
},
|
||||
/**
|
||||
* Simulates `_sendmany` on `bus.bus`.
|
||||
*
|
||||
* @param {Array} notifications
|
||||
*/
|
||||
_mockBusBus__sendmany(notifications) {
|
||||
const values = [];
|
||||
for (const notification of notifications) {
|
||||
const [type, payload] = notification.slice(1, notification.length);
|
||||
values.push({ payload, type });
|
||||
}
|
||||
owl.Component.env.services['bus_service'].trigger('notification', values);
|
||||
},
|
||||
/**
|
||||
* Simulates `_attachment_format` on `ir.attachment`.
|
||||
*
|
||||
|
||||
@@ -18,7 +18,8 @@ import { registry } from '@web/core/registry';
|
||||
import { patchWithCleanup } from "@web/../tests/helpers/utils";
|
||||
import { createWebClient } from "@web/../tests/webclient/helpers";
|
||||
|
||||
const WEBCLIENT_LOAD_ROUTES = [
|
||||
const ROUTES_TO_IGNORE = [
|
||||
'/longpolling/poll',
|
||||
'/web/webclient/load_menus',
|
||||
'/web/dataset/call_kw/res.users/load_views',
|
||||
'/web/dataset/call_kw/res.users/systray_get_activities'
|
||||
@@ -90,7 +91,6 @@ function setupMessagingServiceRegistries({
|
||||
const originalService = busService.start(...arguments);
|
||||
Object.assign(originalService, {
|
||||
_beep() {}, // Do nothing
|
||||
_poll() {}, // Do nothing
|
||||
_registerWindowUnload() {}, // Do nothing
|
||||
updateOption() {},
|
||||
});
|
||||
@@ -156,5 +156,5 @@ function setupMessagingServiceRegistries({
|
||||
|
||||
export {
|
||||
getWebClientReady,
|
||||
WEBCLIENT_LOAD_ROUTES,
|
||||
ROUTES_TO_IGNORE,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { start, startServer } from '@mail/../tests/helpers/test_utils';
|
||||
import { WEBCLIENT_LOAD_ROUTES } from '@mail/../tests/helpers/webclient_setup';
|
||||
import { ROUTES_TO_IGNORE } from '@mail/../tests/helpers/webclient_setup';
|
||||
|
||||
import testUtils from 'web.test_utils';
|
||||
import { clickEdit, patchWithCleanup, selectDropdownItem } from '@web/../tests/helpers/utils';
|
||||
@@ -21,7 +21,7 @@ QUnit.test('list activity widget with no activity', async function (assert) {
|
||||
mockRPC: function (route, args) {
|
||||
if (
|
||||
args.method !== 'get_views' &&
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...WEBCLIENT_LOAD_ROUTES].includes(route)
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...ROUTES_TO_IGNORE].includes(route)
|
||||
) {
|
||||
assert.step(route);
|
||||
}
|
||||
@@ -70,7 +70,7 @@ QUnit.test('list activity widget with activities', async function (assert) {
|
||||
mockRPC: function (route, args) {
|
||||
if (
|
||||
args.method !== 'get_views' &&
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...WEBCLIENT_LOAD_ROUTES].includes(route)
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...ROUTES_TO_IGNORE].includes(route)
|
||||
) {
|
||||
assert.step(route);
|
||||
}
|
||||
@@ -115,7 +115,7 @@ QUnit.test('list activity widget with exception', async function (assert) {
|
||||
mockRPC: function (route, args) {
|
||||
if (
|
||||
args.method !== 'get_views' &&
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...WEBCLIENT_LOAD_ROUTES].includes(route)
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...ROUTES_TO_IGNORE].includes(route)
|
||||
) {
|
||||
assert.step(route);
|
||||
}
|
||||
@@ -172,7 +172,7 @@ QUnit.test('list activity widget: open dropdown', async function (assert) {
|
||||
mockRPC: function (route, args) {
|
||||
if (
|
||||
args.method !== 'get_views' &&
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...WEBCLIENT_LOAD_ROUTES].includes(route)
|
||||
!['/mail/init_messaging', '/mail/load_message_failures', '/longpolling/im_status', ...ROUTES_TO_IGNORE].includes(route)
|
||||
) {
|
||||
assert.step(args.method || route);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ import Widget from "web.Widget";
|
||||
import { uiService } from "@web/core/ui/ui_service";
|
||||
import { ClientActionAdapter, ViewAdapter } from "@web/legacy/action_adapters";
|
||||
import { commandService } from "@web/core/commands/command_service";
|
||||
import { ConnectionAbortedError } from "@web/core/network/rpc_service";
|
||||
import { CustomFavoriteItem } from "@web/search/favorite_menu/custom_favorite_item";
|
||||
import { standaloneAdapter } from "web.OwlCompatibility";
|
||||
|
||||
@@ -215,7 +216,7 @@ export async function addLegacyMockEnvironment(env, legacyParams = {}) {
|
||||
const legacyMockServer = new LegacyMockServer(legacyParams.models, { widget });
|
||||
await legacyMockServer.setup();
|
||||
const originalRPC = env.services.rpc;
|
||||
env.services.rpc = async (...args) => {
|
||||
const rpc = async (...args) => {
|
||||
try {
|
||||
return await originalRPC(...args);
|
||||
} catch (e) {
|
||||
@@ -226,6 +227,15 @@ export async function addLegacyMockEnvironment(env, legacyParams = {}) {
|
||||
}
|
||||
}
|
||||
};
|
||||
env.services.rpc = function () {
|
||||
let rejectFn;
|
||||
const rpcProm = new Promise((resolve, reject) => {
|
||||
rejectFn = reject;
|
||||
rpc(...arguments).then(resolve).catch(reject);
|
||||
});
|
||||
rpcProm.abort = () => rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort"));
|
||||
return rpcProm;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user