From 152a877054bfc5eff1d5adb28ef92aedcac83962 Mon Sep 17 00:00:00 2001 From: juancarmore Date: Fri, 14 Nov 2025 19:14:57 +0100 Subject: [PATCH] test: enhance room creation tests with additional sanitization cases and roomId prefix validation --- .../tests/helpers/assertion-helpers.ts | 10 +- .../api/rooms/bulk-delete-rooms.test.ts | 3 + .../integration/api/rooms/create-room.test.ts | 169 ++++++++++++++++-- .../integration/api/rooms/delete-room.test.ts | 9 +- .../integration/api/rooms/get-room.test.ts | 10 +- .../integration/api/rooms/get-rooms.test.ts | 4 +- 6 files changed, 185 insertions(+), 20 deletions(-) diff --git a/meet-ce/backend/tests/helpers/assertion-helpers.ts b/meet-ce/backend/tests/helpers/assertion-helpers.ts index 55559e6b..b14f0008 100644 --- a/meet-ce/backend/tests/helpers/assertion-helpers.ts +++ b/meet-ce/backend/tests/helpers/assertion-helpers.ts @@ -94,11 +94,12 @@ export const expectSuccessRoomsResponse = ( export const expectSuccessRoomResponse = ( response: Response, roomName: string, + roomIdPrefix?: string, autoDeletionDate?: number, config?: MeetRoomConfig ) => { expect(response.status).toBe(200); - expectValidRoom(response.body, roomName, config, autoDeletionDate); + expectValidRoom(response.body, roomName, roomIdPrefix, config, autoDeletionDate); }; export const expectSuccessRoomConfigResponse = (response: Response, config: MeetRoomConfig) => { @@ -110,6 +111,7 @@ export const expectSuccessRoomConfigResponse = (response: Response, config: Meet export const expectValidRoom = ( room: MeetRoom, name: string, + roomIdPrefix?: string, config?: MeetRoomConfig, autoDeletionDate?: number, autoDeletionPolicy?: MeetRoomAutoDeletionPolicy, @@ -122,7 +124,11 @@ export const expectValidRoom = ( expect(room.roomName).toBeDefined(); expect(room.roomName).toBe(name); expect(room.roomId).not.toBe(''); - expect(room.roomId).toContain(room.roomName.replace(/\s+/g, '')); // Ensure roomId contains the name without spaces + + if (roomIdPrefix) { + expect(room.roomId.startsWith(roomIdPrefix)).toBe(true); + } + expect(room.creationDate).toBeDefined(); if (autoDeletionDate !== undefined) { diff --git a/meet-ce/backend/tests/integration/api/rooms/bulk-delete-rooms.test.ts b/meet-ce/backend/tests/integration/api/rooms/bulk-delete-rooms.test.ts index 99db4129..ff1020cf 100644 --- a/meet-ce/backend/tests/integration/api/rooms/bulk-delete-rooms.test.ts +++ b/meet-ce/backend/tests/integration/api/rooms/bulk-delete-rooms.test.ts @@ -216,6 +216,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.ACTIVE_MEETING, MeetingEndAction.DELETE ); @@ -229,6 +230,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.ACTIVE_MEETING, MeetingEndAction.CLOSE ); @@ -242,6 +244,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.CLOSED, MeetingEndAction.NONE ); diff --git a/meet-ce/backend/tests/integration/api/rooms/create-room.test.ts b/meet-ce/backend/tests/integration/api/rooms/create-room.test.ts index a9e65a5f..1cebb3fb 100644 --- a/meet-ce/backend/tests/integration/api/rooms/create-room.test.ts +++ b/meet-ce/backend/tests/integration/api/rooms/create-room.test.ts @@ -1,14 +1,14 @@ import { afterAll, beforeAll, describe, expect, it } from '@jest/globals'; -import { Express } from 'express'; -import ms from 'ms'; -import request from 'supertest'; -import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js'; -import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js'; import { MeetRecordingAccess, MeetRoomDeletionPolicyWithMeeting, MeetRoomDeletionPolicyWithRecordings } from '@openvidu-meet/typings'; +import { Express } from 'express'; +import ms from 'ms'; +import request from 'supertest'; +import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js'; +import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js'; import { expectValidRoom } from '../../../helpers/assertion-helpers.js'; import { createRoom, deleteAllRooms, startTestServer } from '../../../helpers/request-helpers.js'; @@ -35,7 +35,7 @@ describe('Room API Tests', () => { it('Should create a room without autoDeletionDate (default behavior)', async () => { const room = await createRoom({ - roomName: ' Test Room ' + roomName: 'Test Room' }); expectValidRoom(room, 'Test Room'); }); @@ -43,15 +43,15 @@ describe('Room API Tests', () => { it('Should create a room with a valid autoDeletionDate', async () => { const room = await createRoom({ autoDeletionDate: validAutoDeletionDate, - roomName: ' .,-------}{¡$#<+My Room *123 ' + roomName: 'Room' }); - expectValidRoom(room, 'My Room 123', undefined, validAutoDeletionDate); + expectValidRoom(room, 'Room', 'room', undefined, validAutoDeletionDate); }); it('Should create a room when sending full valid payload', async () => { const payload = { - roomName: ' =Example Room&/ ', + roomName: 'Example Room', autoDeletionDate: validAutoDeletionDate, autoDeletionPolicy: { withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE, @@ -70,7 +70,156 @@ describe('Room API Tests', () => { const room = await createRoom(payload); - expectValidRoom(room, 'Example Room', payload.config, validAutoDeletionDate, payload.autoDeletionPolicy); + expectValidRoom( + room, + 'Example Room', + 'example_room', + payload.config, + validAutoDeletionDate, + payload.autoDeletionPolicy + ); + }); + }); + + describe('Room Name Sanitization Tests', () => { + it('should create room with Spanish characters and generate sanitized roomId', async () => { + const room = await createRoom({ + roomName: 'Habitación José' + }); + expectValidRoom(room, 'Habitación José', 'habitacion_jose'); + }); + + it('should create room with German umlauts and generate sanitized roomId', async () => { + const room = await createRoom({ + roomName: 'Café Müller' + }); + expectValidRoom(room, 'Café Müller', 'cafe_muller'); + }); + + it('should create room with French accents and generate sanitized roomId', async () => { + const room = await createRoom({ + roomName: 'Réunion François' + }); + expectValidRoom(room, 'Réunion François', 'reunion_francois'); + }); + + it('should create room with uppercase letters and convert to lowercase in roomId', async () => { + const room = await createRoom({ + roomName: 'MY ROOM' + }); + expectValidRoom(room, 'MY ROOM', 'my_room'); + }); + + it('should create room with mixed case and convert to lowercase in roomId', async () => { + const room = await createRoom({ + roomName: 'MyRoom123' + }); + expectValidRoom(room, 'MyRoom123', 'myroom123'); + }); + + it('should create room with hyphens and convert to underscores in roomId', async () => { + const room = await createRoom({ + roomName: 'my-test-room' + }); + expectValidRoom(room, 'my-test-room', 'my_test_room'); + }); + + it('should create room with spaces and convert to underscores in roomId', async () => { + const room = await createRoom({ + roomName: 'My Test Room' + }); + expectValidRoom(room, 'My Test Room', 'my_test_room'); + }); + + it('should create room with multiple consecutive spaces and normalize in roomId', async () => { + const room = await createRoom({ + roomName: 'My Test Room' + }); + expectValidRoom(room, 'My Test Room', 'my_test_room'); + }); + + it('should create room with special characters and remove them in roomId', async () => { + const room = await createRoom({ + roomName: 'Room@#$%^&*()123' + }); + expectValidRoom(room, 'Room@#$%^&*()123', 'room123'); + }); + + it('should create room with emojis and remove them in roomId', async () => { + const room = await createRoom({ + roomName: 'Meeting 🎉 Room' + }); + expectValidRoom(room, 'Meeting 🎉 Room', 'meeting_room'); + }); + + it('should create room with leading/trailing underscores and remove them in roomId', async () => { + const room = await createRoom({ + roomName: '__test_room__' + }); + expectValidRoom(room, '__test_room__', 'test_room'); + }); + + it('should create room with leading/trailing hyphens and remove them in roomId', async () => { + const room = await createRoom({ + roomName: '--test-room--' + }); + expectValidRoom(room, '--test-room--', 'test_room'); + }); + + it('should create room with multiple consecutive hyphens/underscores and normalize in roomId', async () => { + const room = await createRoom({ + roomName: 'test___---room' + }); + expectValidRoom(room, 'test___---room', 'test_room'); + }); + + it('should create room with numbers and preserve them in roomId', async () => { + const room = await createRoom({ + roomName: 'Room 123 456' + }); + expectValidRoom(room, 'Room 123 456', 'room_123_456'); + }); + + it('should create room with mix of all sanitization rules', async () => { + const room = await createRoom({ + roomName: 'SALA--Médica #2024 (Niños)' + }); + expectValidRoom(room, 'SALA--Médica #2024 (Niños)', 'sala_medica_2024_ninos'); + }); + + it('should create room with Portuguese characters and generate sanitized roomId', async () => { + const room = await createRoom({ + roomName: 'Reunião São Paulo' + }); + expectValidRoom(room, 'Reunião São Paulo', 'reuniao_sao_paulo'); + }); + + it('should create room with Scandinavian characters and generate sanitized roomId', async () => { + const room = await createRoom({ + roomName: 'Møde Åse' + }); + expectValidRoom(room, 'Møde Åse', 'mde_ase'); + }); + + it('should create room with Chinese characters and use default "room" prefix', async () => { + const room = await createRoom({ + roomName: '会议室' + }); + expectValidRoom(room, '会议室', 'room'); + }); + + it('should create room with only special characters and use default "room" prefix', async () => { + const room = await createRoom({ + roomName: '@#$%^&*()' + }); + expectValidRoom(room, '@#$%^&*()', 'room'); + }); + + it('should create room with emojis only and use default "room" prefix', async () => { + const room = await createRoom({ + roomName: '🎉🎊🎈' + }); + expectValidRoom(room, '🎉🎊🎈', 'room'); }); }); diff --git a/meet-ce/backend/tests/integration/api/rooms/delete-room.test.ts b/meet-ce/backend/tests/integration/api/rooms/delete-room.test.ts index d83a06dd..d12c688d 100644 --- a/meet-ce/backend/tests/integration/api/rooms/delete-room.test.ts +++ b/meet-ce/backend/tests/integration/api/rooms/delete-room.test.ts @@ -91,6 +91,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.ACTIVE_MEETING, MeetingEndAction.DELETE ); @@ -151,6 +152,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.CLOSED, MeetingEndAction.NONE ); @@ -215,6 +217,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.ACTIVE_MEETING, MeetingEndAction.CLOSE ); @@ -228,6 +231,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.CLOSED, MeetingEndAction.NONE ); @@ -264,6 +268,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.ACTIVE_MEETING, MeetingEndAction.DELETE ); @@ -292,6 +297,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.ACTIVE_MEETING, MeetingEndAction.CLOSE ); @@ -306,6 +312,7 @@ describe('Room API Tests', () => { undefined, undefined, undefined, + undefined, MeetRoomStatus.CLOSED, MeetingEndAction.NONE ); @@ -342,7 +349,7 @@ describe('Room API Tests', () => { describe('Delete Room Validation failures', () => { it('should fail when roomId becomes empty after sanitization', async () => { - const response = await deleteRoom('!!-*!@#$%^&*()_+{}|:"<>?'); + const response = await deleteRoom('!!*!@#$%^&*()+{}|:"<>?'); expect(response.status).toBe(422); // Expect an error message indicating the resulting roomId is empty. diff --git a/meet-ce/backend/tests/integration/api/rooms/get-room.test.ts b/meet-ce/backend/tests/integration/api/rooms/get-room.test.ts index 8d752676..1fad37a9 100644 --- a/meet-ce/backend/tests/integration/api/rooms/get-room.test.ts +++ b/meet-ce/backend/tests/integration/api/rooms/get-room.test.ts @@ -29,7 +29,7 @@ describe('Room API Tests', () => { expectValidRoom(createdRoom, 'test-room'); const response = await getRoom(createdRoom.roomId); - expectSuccessRoomResponse(response, 'test-room'); + expectSuccessRoomResponse(response, 'test-room', 'test_room'); }); it('should retrieve a room with custom config', async () => { @@ -51,7 +51,7 @@ describe('Room API Tests', () => { // Retrieve the room by its ID const response = await getRoom(roomId); - expectSuccessRoomResponse(response, 'custom-config', undefined, payload.config); + expectSuccessRoomResponse(response, 'custom-config', 'custom_config', undefined, payload.config); }); it('should retrieve only specified fields when using fields parameter', async () => { @@ -79,7 +79,7 @@ describe('Room API Tests', () => { const response = await getRoom(dirtyRoomId); - expectSuccessRoomResponse(response, 'test-room'); + expectSuccessRoomResponse(response, 'test-room', 'test_room'); }); it('should retrieve a room with autoDeletionDate', async () => { @@ -95,7 +95,7 @@ describe('Room API Tests', () => { // Get the room const response = await getRoom(createdRoom.roomId); - expectSuccessRoomResponse(response, 'deletion-date', validAutoDeletionDate); + expectSuccessRoomResponse(response, 'deletion-date', 'deletion_date', validAutoDeletionDate); }); it('should retrieve a room without moderatorUrl when participant is speaker', async () => { @@ -115,7 +115,7 @@ describe('Room API Tests', () => { describe('Get Room Validation failures', () => { it('should fail when roomId becomes empty after sanitization', async () => { - const response = await getRoom('!!-*!@#$%^&*()_+{}|:"<>?'); + const response = await getRoom('!!*!@#$%^&*()+{}|:"<>?'); expectValidationError(response, 'roomId', 'cannot be empty after sanitization'); }); diff --git a/meet-ce/backend/tests/integration/api/rooms/get-rooms.test.ts b/meet-ce/backend/tests/integration/api/rooms/get-rooms.test.ts index 93576d25..b22851b0 100644 --- a/meet-ce/backend/tests/integration/api/rooms/get-rooms.test.ts +++ b/meet-ce/backend/tests/integration/api/rooms/get-rooms.test.ts @@ -83,7 +83,7 @@ describe('Room API Tests', () => { expectSuccessRoomsResponse(response, 3, 3, true, true); // Rooms are ordered by creation date descending (newest first) rooms.forEach((room: MeetRoom, i: number) => { - expectValidRoom(room, `test-room-${5 - i}`, undefined, validAutoDeletionDate); + expectValidRoom(room, `test-room-${5 - i}`, undefined, undefined, validAutoDeletionDate); }); const nextPageToken = pagination.nextPageToken; @@ -91,7 +91,7 @@ describe('Room API Tests', () => { ({ pagination, rooms } = response.body); expectSuccessRoomsResponse(response, 3, 3, false, false); rooms.forEach((room: MeetRoom, i: number) => { - expectValidRoom(room, `test-room-${2 - i}`, undefined, validAutoDeletionDate); + expectValidRoom(room, `test-room-${2 - i}`, undefined, undefined, validAutoDeletionDate); }); });