[IMP] mail: remove im status route

*: bus, hr_holidays.

The `/bus/im_status` route polls the server every minute in order for
the user im_status to be up to date. This commit removes this poll
by sending the im_status on the bus when updating the current user
presence.

Moreover, before [1], the user bus presence was updated on each poll.
When the user didn't poll for 50 seconds, we assumed the user was
disconnected. Since [1], the bus presence is updated each 30 seconds
by the `im_status` service. This is too frequent: there is no need
to update the user presence so often.

In order not to overhelm the server with unnecessary requests, the update
presence interval as well as the delay to be considered disconnected
have been updated: the former from 30 to 60 seconds, the later from
55 to 65 seconds (assuming that a user that has missed an update
presence tick is disconnected).

[1]: odoo/odoo@a5623d2

closes odoo/odoo#100249

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
tsm-odoo
2022-09-20 11:33:51 +02:00
parent 6c736c8778
commit 5471bd4cb8
22 changed files with 201 additions and 115 deletions
+1 -1
View File
@@ -26,7 +26,7 @@
'bus/static/tests/**/*.js',
],
'web.qunit_mobile_suite_tests': [
'bus/static/tests/helpers/*.js',
'bus/static/tests/helpers/**/*.js',
],
'bus.websocket_worker_assets': [
'web/static/src/legacy/js/promise_extension.js',
-6
View File
@@ -6,12 +6,6 @@ from odoo.http import Controller, request, route
class BusController(Controller):
@route('/bus/im_status', type="json", auth="user")
def im_status(self, partner_ids):
return {
'partners': request.env['res.partner'].with_context(active_test=False).search([('id', 'in', partner_ids)]).read(['im_status'])
}
@route('/bus/get_model_definitions', methods=['POST'], type='http', auth='user')
def get_model_definitions(self, model_names_to_fetch, **kwargs):
return request.make_response(json.dumps(
+2 -2
View File
@@ -43,8 +43,8 @@ class WebsocketController(Controller):
return {'channels': channels, 'notifications': notifications}
@route('/websocket/update_bus_presence', type='http', auth='public', cors='*')
def update_bus_presence(self, inactivity_period):
request.env['ir.websocket']._update_bus_presence(int(inactivity_period))
def update_bus_presence(self, inactivity_period, im_status_ids_by_model):
request.env['ir.websocket']._update_bus_presence(int(inactivity_period), im_status_ids_by_model)
@route('/bus/websocket_worker_bundle', type='http', auth='public', cors='*')
def get_websocket_worker_bundle(self):
+2 -2
View File
@@ -6,11 +6,11 @@ from psycopg2 import OperationalError
from odoo import api, fields, models
from odoo import tools
from odoo.addons.bus.models.bus import TIMEOUT
from odoo.service.model import PG_CONCURRENCY_ERRORS_TO_RETRY
from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
DISCONNECTION_TIMER = TIMEOUT + 5
UPDATE_PRESENCE_DELAY = 60
DISCONNECTION_TIMER = UPDATE_PRESENCE_DELAY + 5
AWAY_TIMER = 1800 # 30 minutes
+12 -1
View File
@@ -8,6 +8,14 @@ class IrWebsocket(models.AbstractModel):
_name = 'ir.websocket'
_description = 'websocket message handling'
def _get_im_status(self, im_status_ids_by_model):
im_status = {}
if 'res.partner' in im_status_ids_by_model:
im_status['partners'] = self.env['res.partner'].with_context(active_test=False).search(
[('id', 'in', im_status_ids_by_model['res.partner'])]).read(['im_status']
)
return im_status
def _build_bus_channel_list(self, channels):
"""
Return the list of channels to subscribe to. Override this
@@ -25,13 +33,16 @@ class IrWebsocket(models.AbstractModel):
channels = set(self._build_bus_channel_list(data['channels']))
dispatch.subscribe(channels, data['last'], self.env.registry.db_name, wsrequest.ws)
def _update_bus_presence(self, inactivity_period):
def _update_bus_presence(self, inactivity_period, im_status_ids_by_model):
if self.env.uid:
self.env['bus.presence'].update(
inactivity_period,
identity_field='user_id',
identity_value=self.env.uid
)
im_status_notification = self._get_im_status(im_status_ids_by_model)
if im_status_ids_by_model:
self.env['bus.bus']._sendone(self.env.user.partner_id, 'bus/im_status', im_status_notification)
@classmethod
def _authenticate(cls):
+47 -25
View File
@@ -1,46 +1,68 @@
/** @odoo-module **/
import { browser } from '@web/core/browser/browser';
import { registry } from '@web/core/registry';
export const UPDATE_BUS_PRESENCE_DELAY = 60000;
/**
* This service updates periodically the user presence in order for the
* im_status to be up to date.
*
* In order to receive bus notifications related to im_status, one must
* register model/ids to monitor to this service.
*/
export const imStatusService = {
dependencies: ['bus_service', 'multi_tab', 'presence'],
start(env, { bus_service, multi_tab, presence }) {
const UPDATE_BUS_PRESENCE_DELAY = 30000;
let updateBusPresenceInterval;
const imStatusModelToIds = {};
let updateBusPresenceTimeout;
function updateBusPresence() {
const now = new Date().getTime();
bus_service.send("update_presence", now - presence.getLastPresence());
}
function stopUpdatingBusPresence() {
clearInterval(updateBusPresenceInterval);
updateBusPresenceInterval = null;
}
function startUpdatingBusPresence() {
if (updateBusPresenceInterval || !multi_tab.isOnMainTab()) {
clearTimeout(updateBusPresenceTimeout);
if (!multi_tab.isOnMainTab()) {
return;
}
updateBusPresence();
updateBusPresenceInterval = setInterval(
updateBusPresence,
UPDATE_BUS_PRESENCE_DELAY,
);
const now = new Date().getTime();
bus_service.send("update_presence", {
inactivity_period: now - presence.getLastPresence(),
im_status_ids_by_model: { ...imStatusModelToIds },
});
updateBusPresenceTimeout = browser.setTimeout(updateBusPresence, UPDATE_BUS_PRESENCE_DELAY);
}
// wait for im_status model/ids to be registered before starting.
browser.setTimeout(updateBusPresence, 250);
multi_tab.bus.addEventListener('become_main_tab', updateBusPresence);
bus_service.addEventListener('reconnect', updateBusPresence);
multi_tab.bus.addEventListener('no_longer_main_tab', () => clearTimeout(updateBusPresenceTimeout));
bus_service.addEventListener('disconnect', () => clearTimeout(updateBusPresenceTimeout));
if (multi_tab.isOnMainTab()) {
startUpdatingBusPresence();
}
multi_tab.bus.addEventListener('become_main_tab', startUpdatingBusPresence);
bus_service.addEventListener('reconnect', startUpdatingBusPresence);
multi_tab.bus.addEventListener('no_longer_main_tab', stopUpdatingBusPresence);
bus_service.addEventListener('disconnect', stopUpdatingBusPresence);
return {
/**
* Register model/ids whose im_status should be monitored.
* Notification related to the im_status are then sent
* through the bus. Overwrite registration if already
* present.
*
* @param {string} model model related to the given ids.
* @param {Number[]} ids ids whose im_status should be
* monitored.
*/
registerToImStatus(model, ids) {
if (!ids.length) {
return this.unregisterFromImStatus(model);
}
imStatusModelToIds[model] = ids;
},
/**
* Unregister model from im_status notifications.
*
* @param {string} model model to unregister.
*/
unregisterFromImStatus(model) {
delete imStatusModelToIds[model];
},
};
},
};
+20 -2
View File
@@ -12,7 +12,13 @@ patch(MockServer.prototype, 'bus', {
init() {
this._super(...arguments);
Object.assign(this, TEST_USER_IDS);
this.websocketWorker = patchWebsocketWorkerWithCleanup();
const self = this;
this.websocketWorker = patchWebsocketWorkerWithCleanup({
_sendToServer(message) {
self._performWebsocketRequest(message);
this._super(message);
},
});
this.pendingLongpollingPromise = null;
this.notificationsToBeResolved = [];
this.lastBusNotificationId = 0;
@@ -22,6 +28,19 @@ patch(MockServer.prototype, 'bus', {
// Private
//--------------------------------------------------------------------------
/**
* @param {Object} message Message sent through the websocket to the
* server.
* @param {string} [message.event_name]
* @param {any} [message.data]
*/
_performWebsocketRequest({ event_name, data }) {
if (event_name === 'update_presence') {
const { inactivity_period, im_status_ids_by_model } = data;
this._mockIrWebsocket__updatePresence(inactivity_period, im_status_ids_by_model);
}
},
/**
* @override
*/
@@ -71,7 +90,6 @@ patch(MockServer.prototype, 'bus', {
this.websocketWorker.broadcast('notification', values);
},
/**
* Simulate the lost of the connection by simulating a closeEvent on
* the worker websocket.
@@ -0,0 +1,28 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { MockServer } from "@web/../tests/helpers/mock_server";
patch(MockServer.prototype, 'bus/models/ir_websocket', {
/**
* Simulates `_update_presence` on `ir.websocket`.
*
* @param inactivityPeriod
* @param imStatusIdsByModel
*/
_mockIrWebsocket__updatePresence(inactivityPeriod, imStatusIdsByModel) {
this._mockBusBus__sendone(this.currentPartnerId, 'bus/im_status', this._mockIrWebsocket__getImStatus(imStatusIdsByModel));
},
/**
* Simulates `_get_im_status` on `ir.websocket`.
*
* @param {Object} imStatusIdsByModel
* @param {Number[]|undefined} res.partner ids of res.partners whose im_status
* should be monitored.
*/
_mockIrWebsocket__getImStatus({ 'res.partner': partnerIds }) {
return {
'partners': this.mockSearchRead('res.partner', [[['id', 'in', partnerIds]]], { context: { 'active_test': false }, fields: ['im_status'] })
};
},
});
+1 -1
View File
@@ -766,7 +766,7 @@ class WebsocketRequest:
if event_name == 'subscribe':
ir_websocket._subscribe(data)
if event_name == 'update_presence':
ir_websocket._update_bus_presence(data)
ir_websocket._update_bus_presence(**data)
def _get_session(self):
session = root.session_store.get(self.ws._session.sid)
@@ -1,5 +1,7 @@
/** @odoo-module **/
import { UPDATE_BUS_PRESENCE_DELAY } from '@bus/im_status_service';
import { start, startServer } from '@mail/../tests/helpers/test_utils';
QUnit.module('hr_holidays', {}, function () {
@@ -18,7 +20,7 @@ QUnit.test('on leave & online', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -27,7 +29,7 @@ QUnit.test('on leave & online', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.hasClass(
document.querySelector('.o_PersonaImStatusIcon_icon'),
'o-online',
@@ -52,7 +54,7 @@ QUnit.test('on leave & away', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -61,7 +63,7 @@ QUnit.test('on leave & away', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.hasClass(
document.querySelector('.o_PersonaImStatusIcon_icon'),
'o-away',
@@ -86,7 +88,7 @@ QUnit.test('on leave & offline', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -95,7 +97,7 @@ QUnit.test('on leave & offline', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.hasClass(
document.querySelector('.o_PersonaImStatusIcon_icon'),
'o-offline',
+2 -2
View File
@@ -9,8 +9,8 @@ from odoo.addons.bus.websocket import wsrequest
class IrWebsocket(models.AbstractModel):
_inherit = 'ir.websocket'
def _update_bus_presence(self, inactivity_period):
super()._update_bus_presence(inactivity_period)
def _update_bus_presence(self, inactivity_period, im_status_ids_by_model):
super()._update_bus_presence(inactivity_period, im_status_ids_by_model)
# This method can either be called due to an http or a
# websocket request. The request itself is necessary to
# retrieve the current guest. Let's retrieve the proper
-7
View File
@@ -50,10 +50,3 @@ class MailChatController(BusController):
return []
else:
return channel._channel_fetch_message(last_id, limit)
@route('/bus/im_status', type="json", auth="user")
def im_status(self, partner_ids, guest_ids=None):
im_status = super().im_status(partner_ids)
if guest_ids:
im_status['guests'] = request.env['mail.guest'].sudo().with_context(active_test=False).search([('id', 'in', guest_ids)]).read(['im_status'])
return im_status
+8 -2
View File
@@ -6,6 +6,12 @@ from odoo.addons.bus.websocket import wsrequest
class IrWebsocket(models.AbstractModel):
_inherit = 'ir.websocket'
def _get_im_status(self, data):
im_status = super()._get_im_status(data)
if 'mail.guest' in data:
im_status['guests'] = self.env['mail.guest'].sudo().with_context(active_test=False).search([('id', 'in', data['mail.guest'])]).read(['im_status'])
return im_status
def _build_bus_channel_list(self, channels):
# This method can either be called due to an http or a
# websocket request. The request itself is necessary to
@@ -26,8 +32,8 @@ class IrWebsocket(models.AbstractModel):
channels.append(mail_channel)
return super()._build_bus_channel_list(channels)
def _update_bus_presence(self, inactivity_period):
super()._update_bus_presence(inactivity_period)
def _update_bus_presence(self, inactivity_period, im_status_ids_by_model):
super()._update_bus_presence(inactivity_period, im_status_ids_by_model)
if not self.env.uid:
# This method can either be called due to an http or a
# websocket request. The request itself is necessary to
+26 -29
View File
@@ -17,6 +17,8 @@ registerModel({
this.refreshIsNotificationPermissionDefault();
},
_willDelete() {
this.env.services['im_status'].unregisterFromImStatus('res.partner');
this.env.services['im_status'].unregisterFromImStatus('mail.guest');
this.env.bus.removeEventListener('window_focus', this._handleGlobalWindowFocus);
delete odoo.__DEBUG__.messaging;
},
@@ -93,9 +95,6 @@ registerModel({
const { message, ...options } = params;
return this.env.services.notification.add(message, options);
},
onFetchImStatusTimerTimeout() {
this.startFetchImStatus();
},
/**
* Opens a chat with the provided person and returns it.
*
@@ -221,36 +220,19 @@ registerModel({
isNotificationPermissionDefault: Boolean(browserNotification) && browserNotification.permission === 'default',
});
},
async startFetchImStatus() {
this.update({
fetchImStatusTimer: { doReset: this.fetchImStatusTimer ? true : undefined },
});
updateImStatusRegistration() {
const partnerIds = [];
for (const partner of this.models['Partner'].all()) {
if (partner.im_status !== 'im_partner' && !partner.is_public) {
partnerIds.push(partner.id);
}
}
if (partnerIds.length === 0) {
return;
}
const guestIds = [];
for (const guest of this.models['Guest'].all()) {
guestIds.push(guest.id);
}
if (partnerIds.length !== 0 || guestIds.length !== 0) {
const dataList = await this.messaging.rpc({
route: '/bus/im_status',
params: {
partner_ids: partnerIds,
guest_ids: guestIds,
},
}, { shadow: true });
this.models['Partner'].insert(dataList.partners);
if (dataList.guests) {
this.models['Guest'].insert(dataList.guests);
}
}
this.env.services['im_status'].registerToImStatus('res.partner', partnerIds);
this.env.services['im_status'].registerToImStatus('mail.guest', guestIds);
},
/**
* @private
@@ -329,6 +311,14 @@ registerModel({
this.env.services.bus_service.forceUpdateChannels();
}
},
/**
* @private
*/
_onChangeAllPersonas() {
if (this.isInitialized) {
this.updateImStatusRegisterThrottle.do();
}
},
/**
* @private
*/
@@ -344,6 +334,9 @@ registerModel({
allMailboxes: many('Mailbox', {
inverse: 'messagingAsAnyMailbox',
}),
allPersonas: many('Persona', {
inverse: 'messagingAsAnyPersona',
}),
/**
* Inverse of the messaging field present on all models. This field
* therefore contains all existing records.
@@ -404,12 +397,6 @@ registerModel({
isCausal: true,
readonly: true,
}),
fetchImStatusTimer: one('Timer', {
inverse: 'messagingOwnerAsFetchImStatusTimer',
}),
fetchImStatusTimerDuration: attr({
default: 50 * 1000,
}),
hasLinkPreviewFeature: attr(),
history: one('Mailbox', {
default: {},
@@ -516,6 +503,12 @@ registerModel({
isCausal: true,
readonly: true,
}),
updateImStatusRegisterThrottle: one('Throttle', {
compute() {
return { func: this.updateImStatusRegistration };
},
inverse: 'messagingAsUpdateImStatusRegister',
}),
userSetting: one('UserSetting', {
default: {},
isCausal: true,
@@ -530,5 +523,9 @@ registerModel({
dependencies: ['allCurrentClientThreads'],
methodName: '_onChangeAllCurrentClientThreads',
},
{
dependencies: ['allPersonas'],
methodName: '_onChangeAllPersonas',
},
],
});
@@ -33,7 +33,7 @@ registerModel({
discuss.openInitThread();
}
if (this.messaging.currentUser) {
this.messaging.startFetchImStatus();
this.messaging.updateImStatusRegistration();
this._loadMessageFailures();
}
},
@@ -48,6 +48,8 @@ registerModel({
const proms = notifications.map(message => {
if (typeof message === 'object') {
switch (message.type) {
case 'bus/im_status':
return this._handleNotificationBusImStatus(message.payload);
case 'ir.attachment/delete':
return this._handleNotificationAttachmentDelete(message.payload);
case 'mail.channel.member/seen':
@@ -149,6 +151,20 @@ registerModel({
* @param {Object} message
*/
_handleNotification(message) {},
/**
* @private
* @param {Object} payload
* @param {Object[]} [payload.partners]
* @param {Object[]|undefined} [payload.guests]
*/
_handleNotificationBusImStatus({ partners, guests }) {
if (partners) {
this.models['Partner'].insert(partners);
}
if (guests) {
this.models['Guest'].insert(guests);
}
},
/**
* @private
* @param {Object} payload
+5
View File
@@ -60,6 +60,11 @@ registerModel({
im_status: attr({
compute: '_computeImStatus',
}),
messagingAsAnyPersona: one('Messaging', {
default: {},
inverse: 'allPersonas',
}),
name: attr({
compute: '_computeName',
}),
@@ -53,6 +53,9 @@ registerModel({
if (this.threadAsThrottleNotifyCurrentPartnerTypingStatus) {
return 2.5 * 1000;
}
if (this.messagingAsUpdateImStatusRegister) {
return 10 * 1000;
}
return clear();
},
},
@@ -75,6 +78,10 @@ registerModel({
* Inner function to be invoked and throttled.
*/
func: attr(),
messagingAsUpdateImStatusRegister: one('Messaging', {
identifying: true,
inverse: 'updateImStatusRegisterThrottle',
}),
shouldInvoke: attr({
default: false,
}),
-11
View File
@@ -33,9 +33,6 @@ registerModel({
if (this.messageViewOwnerAsHighlight) {
return 2 * 1000;
}
if (this.messagingOwnerAsFetchImStatusTimer) {
return this.messagingOwnerAsFetchImStatusTimer.fetchImStatusTimerDuration;
}
if (this.rtcSessionOwnerAsBroadcast) {
return 3 * 1000;
}
@@ -74,10 +71,6 @@ registerModel({
this.messageViewOwnerAsHighlight.onHighlightTimerTimeout();
return;
}
if (this.messagingOwnerAsFetchImStatusTimer) {
this.messagingOwnerAsFetchImStatusTimer.onFetchImStatusTimerTimeout();
return;
}
if (this.rtcSessionOwnerAsBroadcast) {
this.rtcSessionOwnerAsBroadcast.onBroadcastTimeout();
return;
@@ -134,10 +127,6 @@ registerModel({
compute: '_computeDuration',
required: true,
}),
messagingOwnerAsFetchImStatusTimer: one('Messaging', {
identifying: true,
inverse: 'fetchImStatusTimer',
}),
messageViewOwnerAsHighlight: one('MessageView', {
identifying: true,
inverse: 'highlightTimer',
@@ -62,12 +62,6 @@ patch(MockServer.prototype, 'mail', {
*/
async _performRPC(route, args) {
// routes
if (route === '/bus/im_status') {
const { partner_ids } = args;
return {
'partners': this.pyEnv['res.partner'].searchRead([['id', 'in', partner_ids]], { context: { 'active_test': false }, fields: ['im_status'] })
};
}
if (route === '/mail/message/post') {
if (args.thread_model === 'mail.channel') {
return this._mockMailChannelMessagePost(args.thread_id, args.post_data, args.context);
@@ -1,6 +1,7 @@
/** @odoo-module **/
import { busService } from '@bus/services/bus_service';
import { imStatusService } from '@bus/im_status_service';
import { multiTabService } from '@bus/multi_tab_service';
import { makeMultiTabToLegacyEnv } from '@bus/services/legacy/make_multi_tab_to_legacy_env';
import { makeBusServiceToLegacyEnv } from '@bus/services/legacy/make_bus_service_to_legacy_env';
@@ -84,6 +85,7 @@ function setupMessagingServiceRegistries({
services = {
bus_service: busService,
im_status: imStatusService,
messaging: messagingService,
messagingValues,
presence: makeFakePresenceService({
@@ -1,5 +1,7 @@
/** @odoo-module **/
import { UPDATE_BUS_PRESENCE_DELAY } from '@bus/im_status_service';
import { start, startServer } from '@mail/../tests/helpers/test_utils';
QUnit.module('mail', {}, function () {
@@ -18,7 +20,7 @@ QUnit.test('initially online', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -27,7 +29,7 @@ QUnit.test('initially online', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-online`).length,
1,
@@ -47,7 +49,7 @@ QUnit.test('initially offline', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -56,7 +58,7 @@ QUnit.test('initially offline', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-offline`).length,
1,
@@ -76,7 +78,7 @@ QUnit.test('initially away', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -85,7 +87,7 @@ QUnit.test('initially away', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-away`).length,
1,
@@ -105,7 +107,7 @@ QUnit.test('change icon on change partner im_status', async function (assert) {
model: 'mail.channel',
res_id: mailChannelId,
});
const { advanceTime, afterNextRender, messaging, openDiscuss } = await start({
const { advanceTime, afterNextRender, openDiscuss } = await start({
discuss: {
params: {
default_active_id: mailChannelId,
@@ -114,7 +116,7 @@ QUnit.test('change icon on change partner im_status', async function (assert) {
hasTimeControl: true,
});
await openDiscuss();
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-online`).length,
1,
@@ -122,7 +124,7 @@ QUnit.test('change icon on change partner im_status', async function (assert) {
);
pyEnv['res.partner'].write([partnerId], { im_status: 'offline' });
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-offline`).length,
1,
@@ -130,7 +132,7 @@ QUnit.test('change icon on change partner im_status', async function (assert) {
);
pyEnv['res.partner'].write([partnerId], { im_status: 'away' });
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-away`).length,
1,
@@ -138,7 +140,7 @@ QUnit.test('change icon on change partner im_status', async function (assert) {
);
pyEnv['res.partner'].write([partnerId], { im_status: 'online' });
await afterNextRender(() => advanceTime(messaging.fetchImStatusTimerDuration));
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
assert.strictEqual(
document.querySelectorAll(`.o_PersonaImStatusIcon.o-online`).length,
1,