bus/static/tests/helpers/mock_server.js
Данил Воробьев 9ae41c29a2 initial commit
2024-05-03 12:03:07 +00:00

173 lines
6.4 KiB
JavaScript

/** @odoo-module **/
import { TEST_USER_IDS } from "@bus/../tests/helpers/test_constants";
import { patchWebsocketWorkerWithCleanup } from "@bus/../tests/helpers/mock_websocket";
import { patch } from "@web/core/utils/patch";
import { MockServer } from "@web/../tests/helpers/mock_server";
import { registry } from "@web/core/registry";
QUnit.testDone(() => {
const callbackRegistry = registry.category("mock_server_websocket_callbacks");
callbackRegistry.getEntries().map(([key]) => callbackRegistry.remove(key));
});
patch(MockServer.prototype, {
init() {
super.init(...arguments);
Object.assign(this, TEST_USER_IDS);
const self = this;
this.notificationQueue = [];
this.websocketWorker = patchWebsocketWorkerWithCleanup({
_sendToServer(message) {
self._performWebsocketRequest(message);
super._sendToServer(message);
},
});
this.lastBusNotificationId = 0;
this.channelsByUser = {};
for (const modelName in this.models) {
const records = Array.isArray(this.models[modelName].records)
? this.models[modelName].records
: [];
for (const record of records) {
Object.defineProperty(record, "__model", { value: modelName });
}
}
},
mockCreate(modelName, valsList, kwargs = {}) {
const result = super.mockCreate(modelName, valsList, kwargs);
const returnArrayOfIds = Array.isArray(result);
const recordIds = Array.isArray(result) ? result : [result];
for (const recordId of recordIds) {
const record = this.models[modelName].records.find((r) => r.id === recordId);
Object.defineProperty(record, "__model", { value: modelName });
}
return returnArrayOfIds ? recordIds : recordIds[0];
},
mockSearchRead(modelName, domain, kwargs = {}) {
const records = super.mockSearchRead(modelName, domain, kwargs);
for (const record of records) {
Object.defineProperty(record, "__model", { value: modelName });
}
return records;
},
//--------------------------------------------------------------------------
// 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);
} else if (event_name === "subscribe") {
const { channels } = data;
this.channelsByUser[this.pyEnv?.currentUser] = this.pyEnv
? this._mockIrWebsocket__buildBusChannelList(channels)
: channels;
}
const callbackFn = registry
.category("mock_server_websocket_callbacks")
.get(event_name, null);
if (callbackFn) {
callbackFn(data);
}
},
/**
* 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) {
if (!notifications.length) {
return;
}
const values = [];
const authenticatedUserId =
"res.users" in this.models
? this.pyEnv.cookie.get("authenticated_user_sid")
: undefined;
const authenticatedUser = authenticatedUserId
? this.pyEnv["res.users"].searchRead([["id", "=", authenticatedUserId]], {
context: { active_test: false },
})[0]
: null;
const channels =
this.channelsByUser[authenticatedUser] ?? this._mockIrWebsocket__buildBusChannelList();
notifications = notifications.filter(([target]) =>
channels.some((channel) => {
if (typeof target === "string") {
return channel === target;
}
if (Array.isArray(channel) !== Array.isArray(target)) {
return false;
}
if (Array.isArray(channel)) {
const { __model: cModel, id: cId } = channel[0];
const { __model: tModel, id: tId } = target[0];
return cModel === tModel && cId === tId && channel[1] === target[1];
}
return channel?.__model === target.__model && channel?.id === target?.id;
})
);
if (notifications.length === 0) {
return;
}
for (const notification of notifications) {
const [type, payload] = notification.slice(1, notification.length);
values.push({ id: ++this.lastBusNotificationId, message: { payload, type } });
}
this.notificationQueue.push(...values);
if (this.notificationQueue.length === values.length) {
this._planNotificationSending();
}
},
/**
* Helper to send the pending notifications to the client. This method is
* push to the micro task queue to simulate server-side batching of
* notifications.
*/
_planNotificationSending() {
queueMicrotask(() => {
if (this.debug) {
console.group("%c[BUS]", "color: #c6e; font-weight: bold;");
for (const { message } of this.notificationQueue) {
console.log(message.type, message.payload);
}
console.groupEnd();
}
this.websocketWorker.broadcast("notification", this.notificationQueue);
this.notificationQueue = [];
});
},
/**
* Simulate the lost of the connection by simulating a closeEvent on
* the worker websocket.
*
* @param {number} closeCode the code to close the connection with.
*/
_simulateConnectionLost(closeCode) {
this.websocketWorker.websocket.close(closeCode);
},
});