fix(api): update WebsocketGateway unit tests

This commit is contained in:
yassinedorbozgithub 2025-05-12 18:18:02 +01:00
parent e203485d75
commit 22ef79b05f
2 changed files with 111 additions and 15 deletions

View File

@ -8,6 +8,7 @@
import { INestApplication } from '@nestjs/common';
import { Socket, io } from 'socket.io-client';
import { v4 as uuidv4 } from 'uuid';
import {
closeInMongodConnection,
@ -16,12 +17,16 @@ import {
import { buildTestingMocks } from '@/utils/test/utils';
import { SocketEventDispatcherService } from './services/socket-event-dispatcher.service';
import { Room } from './types';
import { WebsocketGateway } from './websocket.gateway';
describe('WebsocketGateway', () => {
let gateway: WebsocketGateway;
let app: INestApplication;
let ioClient: Socket;
let createSocket: (index: number) => Socket;
let sockets: Socket[];
let sessionIds: string[];
let validSessionIds: string[];
beforeAll(async () => {
// Instantiate the app
@ -39,12 +44,20 @@ describe('WebsocketGateway', () => {
// Get the gateway instance from the app instance
gateway = app.get<WebsocketGateway>(WebsocketGateway);
// Create a new client that will interact with the gateway
ioClient = io('http://localhost:3000', {
autoConnect: false,
transports: ['websocket', 'polling'],
// path: '/socket.io/?EIO=4&transport=websocket&channel=web-channel',
query: { EIO: '4', transport: 'websocket', channel: 'web-channel' },
});
sessionIds = [uuidv4(), uuidv4(), uuidv4()];
validSessionIds = [sessionIds[0], sessionIds[2]];
createSocket = (index: number) =>
io('http://localhost:3000', {
autoConnect: false,
transports: ['websocket', 'polling'],
// path: '/socket.io/?EIO=4&transport=websocket&channel=web-channel',
query: { EIO: '4', transport: 'websocket', channel: 'web-channel' },
extraHeaders: { sessionid: sessionIds[index] },
});
sockets = sessionIds.map((e, index) => createSocket(index));
await app.listen(3000);
});
@ -59,31 +72,102 @@ describe('WebsocketGateway', () => {
});
it('should connect successfully', async () => {
const socketClient = ioClient.connect();
const [socket1] = sockets;
socket1.connect();
await new Promise<void>((resolve) => {
socketClient.on('connect', () => {
socket1.on('connect', async () => {
expect(true).toBe(true);
resolve();
});
});
socketClient.disconnect();
socket1.disconnect();
});
it('should emit "OK" on "healthcheck"', async () => {
const socketClient = ioClient.connect();
const [socket1] = sockets;
socket1.connect();
await new Promise<void>((resolve) => {
socketClient.on('connect', () => {
socketClient.emit('healthcheck', 'Hello world!');
socketClient.on('event', (data) => {
socket1.on('connect', () => {
socket1.emit('healthcheck', 'Hello world!');
socket1.on('event', (data) => {
expect(data).toBe('OK');
resolve();
});
});
});
socketClient.disconnect();
socket1.disconnect();
});
describe('joinNotificationSockets', () => {
it('should join socket1 and socket3 to room MESSAGE', async () => {
const [socket1, , socket3] = sockets;
[socket1, , socket3].forEach((socket) => socket?.connect());
for (const socket of [socket1, , socket3]) {
if (socket) {
await new Promise<void>((resolve) => {
socket.on('connect', async () => {
resolve();
});
});
}
}
jest.spyOn(gateway, 'getNotificationSockets').mockResolvedValueOnce(
(await gateway.io.fetchSockets()).filter(({ handshake }) => {
const uuid = handshake.headers.sessionid?.toString() || '';
return validSessionIds.includes(uuid);
}),
);
await gateway.joinNotificationSockets('sessionId', Room.MESSAGE);
expect(gateway.getNotificationSockets).toHaveBeenCalledWith('sessionId');
gateway.io.to(Room.MESSAGE).emit('message', { data: 'OK' });
for (const socket of [socket1, , socket3]) {
if (socket)
await new Promise<void>((resolve) => {
socket.on('message', async ({ data }) => {
expect(data).toBe('OK');
resolve();
});
});
}
sockets.forEach((socket) => socket.disconnect());
});
it('should throw an error when socket array is empty', async () => {
jest.spyOn(gateway, 'getNotificationSockets').mockResolvedValueOnce([]);
expect(gateway.getNotificationSockets).toHaveBeenCalledWith('sessionId');
await expect(
gateway.joinNotificationSockets('sessionId', Room.MESSAGE),
).rejects.toThrow('No notification sockets found!');
});
it('should throw an error with empty sessionId', async () => {
await expect(
gateway.joinNotificationSockets('', Room.MESSAGE),
).rejects.toThrow('SessionId is required!');
});
});
describe('getNotificationSockets', () => {
it('should throw an error with empty sessionId', async () => {
await expect(gateway.getNotificationSockets('')).rejects.toThrow(
'SessionId is required!',
);
});
});
});

View File

@ -416,6 +416,10 @@ export class WebsocketGateway
async getNotificationSockets(
sessionId: string,
): Promise<RemoteSocket<DefaultEventsMap, any>[]> {
if (!sessionId) {
throw new Error('SessionId is required!');
}
return (await this.io.fetchSockets()).filter(
({ handshake, data }) =>
!handshake.query.channel && data.sessionID === sessionId,
@ -429,8 +433,16 @@ export class WebsocketGateway
* @param room - the joined room name
*/
async joinNotificationSockets(sessionId: string, room: Room): Promise<void> {
if (!sessionId) {
throw new Error('SessionId is required!');
}
const notificationSockets = await this.getNotificationSockets(sessionId);
if (!notificationSockets.length) {
throw new Error('No notification sockets found!');
}
notificationSockets.forEach((notificationSocket) =>
notificationSocket.join(room),
);