import { afterEach, beforeAll, describe, expect, it } from '@jest/globals'; import { bulkDeleteRooms, createRoom, deleteAllRooms, disconnectFakeParticipants, getRoom, joinFakeParticipant, sleep, startTestServer } from '../../../helpers/request-helpers.js'; describe('Room API Tests', () => { beforeAll(() => { startTestServer(); }); afterEach(async () => { // Remove all rooms created await disconnectFakeParticipants(); await deleteAllRooms(); }); describe('Bulk Delete Room Tests', () => { it('should return 204 when room does not exist (idempotent deletion)', async () => { // The roomId will be transformed to string const response = await bulkDeleteRooms([{ invalid: 'format' }], true); expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); }); it('should delete room (204) with invalid force parameter when no participants exist', async () => { const { roomId } = await createRoom({ roomName: 'test-invalid-force' }); const response = await bulkDeleteRooms([roomId]); //The bulk operation for only one room should be the same as deleting the room expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); }); it('should mark room for deletion (202) with invalid force parameter when participants exist', async () => { const { roomId } = await createRoom({ roomName: 'test-invalid-force' }); await joinFakeParticipant(roomId, 'test-participant-1'); const response = await bulkDeleteRooms([roomId]); //The bulk operation for only one room should be the same as deleting the room expect(response.status).toBe(202); expect(response.body.message).toContain('marked for deletion'); }); it('should delete room (204) with force=true parameter when no participants exist', async () => { const { roomId } = await createRoom({ roomName: 'test-force' }); const response = await bulkDeleteRooms([roomId], true); //The bulk operation for only one room should be the same as deleting the room expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); }); it('should delete room (204) with force=true parameter when participants exist', async () => { const { roomId } = await createRoom({ roomName: 'test-force' }); await joinFakeParticipant(roomId, 'test-participant-1'); const response = await bulkDeleteRooms([roomId], true); //The bulk operation for only one room should be the same as deleting the room expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); }); it('should successfully delete the room requesting the same roomId multiple times', async () => { const { roomId } = await createRoom({ roomName: 'test-duplicate' }); const response = await bulkDeleteRooms([roomId, roomId, roomId], true); expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); }); it('should successfully delete valid roomIds while ignoring invalid ones', async () => { const { roomId } = await createRoom({ roomName: 'test-invalid-force' }); const response = await bulkDeleteRooms([roomId, '!!@##$']); expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); }); it('should successfully delete multiple rooms with valid roomIds', async () => { // Create test rooms const [room1, room2] = await Promise.all([ createRoom({ roomName: 'test-bulk-1' }), createRoom({ roomName: 'test-bulk-2' }) ]); // Delete both rooms const response = await bulkDeleteRooms([room1.roomId, room2.roomId]); expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); // Verify that the rooms are deleted const getRoom1 = await getRoom(room1.roomId); const getRoom2 = await getRoom(room2.roomId); expect(getRoom1.status).toBe(404); expect(getRoom2.status).toBe(404); expect(getRoom1.body.message).toContain(`'${room1.roomId}' does not exist`); expect(getRoom2.body.message).toContain(`'${room2.roomId}' does not exist`); }); it('should successfully marked for deletion multiple rooms with valid roomIds', async () => { // Create test rooms const [room1, room2] = await Promise.all([ createRoom({ roomName: 'test-bulk-1' }), createRoom({ roomName: 'test-bulk-2' }) ]); await Promise.all([ joinFakeParticipant(room1.roomId, 'test-participant-1'), joinFakeParticipant(room2.roomId, 'test-participant-2') ]); // Delete both rooms const response = await bulkDeleteRooms([room1.roomId, room2.roomId]); expect(response.status).toBe(202); expect(response.body.message).toContain(`Rooms '${room1.roomId}, ${room2.roomId}' marked for deletion`); expect(response.body.deleted).toBeUndefined(); // Verify that the rooms are marked for deletion const getRoom1 = await getRoom(room1.roomId); const getRoom2 = await getRoom(room2.roomId); expect(getRoom1.status).toBe(200); expect(getRoom2.status).toBe(200); expect(getRoom1.body.roomId).toBe(room1.roomId); expect(getRoom2.body.roomId).toBe(room2.roomId); expect(getRoom1.body.markedForDeletion).toBe(true); expect(getRoom2.body.markedForDeletion).toBe(true); }); it('should sanitize roomIds before deleting', async () => { // Create a test room const { roomId } = await createRoom({ roomName: 'test-sanitize' }); const response = await bulkDeleteRooms([roomId + '!!@##$']); expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); const deletedRoom = await getRoom(roomId); expect(deletedRoom.status).toBe(404); expect(deletedRoom.body.message).toContain(`'${roomId}' does not exist`); }); it('should delete rooms when force=true and participants exist', async () => { // Create test rooms const [room1, room2] = await Promise.all([ createRoom({ roomName: 'test-bulk-1' }), createRoom({ roomName: 'test-bulk-2' }) ]); // Join a participant to the rooms await Promise.all([ joinFakeParticipant(room1.roomId, 'test-participant-1'), joinFakeParticipant(room2.roomId, 'test-participant-2') ]); // Attempt to delete the rooms with force=false const response = await bulkDeleteRooms([room1.roomId, room2.roomId], true); expect(response.status).toBe(204); expect(response.body).toStrictEqual({}); // Verify that the rooms are deleted await sleep('1s'); // Wait a bit for the meetings to be closed and the rooms deleted const deletedRoom1 = await getRoom(room1.roomId); const deletedRoom2 = await getRoom(room2.roomId); expect(deletedRoom1.status).toBe(404); expect(deletedRoom1.body.message).toContain(`'${room1.roomId}' does not exist`); expect(deletedRoom2.status).toBe(404); expect(deletedRoom2.body.message).toContain(`'${room2.roomId}' does not exist`); }); it('should return mixed results (200) when some rooms are deleted and others marked for deletion', async () => { // Create rooms const room1 = await createRoom({ roomName: 'empty-room' }); const room2 = await createRoom({ roomName: 'occupied-room' }); // Add participant to only one room await joinFakeParticipant(room2.roomId, 'test-participant'); // Delete both rooms (without force) const response = await bulkDeleteRooms([room1.roomId, room2.roomId], false); // Should return 200 with mixed results expect(response.status).toBe(200); expect(response.body.deleted).toHaveLength(1); expect(response.body.deleted).toContain(room1.roomId); expect(response.body.markedForDeletion).toHaveLength(1); expect(response.body.markedForDeletion).toContain(room2.roomId); // Verify deletion state const getRoom1 = await getRoom(room1.roomId); const getRoom2 = await getRoom(room2.roomId); expect(getRoom1.status).toBe(404); expect(getRoom2.status).toBe(200); }); it('should handle a large number of room IDs', async () => { // Create 20+ rooms and test deletion const rooms = await Promise.all( Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` })) ); const response = await bulkDeleteRooms(rooms.map((r) => r.roomId)); expect(response.status).toBe(204); // Verify all rooms are deleted for (const room of rooms) { const getResponse = await getRoom(room.roomId); expect(getResponse.status).toBe(404); } }); it('should handle a large number of room IDs with mixed valid and invalid IDs', async () => { // Create 20+ rooms and test deletion const rooms = await Promise.all( Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` })) ); await joinFakeParticipant(rooms[0].roomId, 'test-participant-1'); const response = await bulkDeleteRooms([ ...rooms.map((r) => r.roomId), '!!@##$', ',,,,', 'room-1', 'room-2' ]); expect(response.status).toBe(200); // Verify all valid rooms are deleted for (const room of rooms) { if (room.roomId === rooms[0].roomId) { continue; // Skip the room with a participant } const getResponse = await getRoom(room.roomId); expect(getResponse.status).toBe(404); } // Verify the room with a participant is marked for deletion const getResponse = await getRoom(rooms[0].roomId); expect(getResponse.status).toBe(200); expect(getResponse.body.markedForDeletion).toBe(true); expect(getResponse.body.roomId).toBe(rooms[0].roomId); }); }); describe('Bulk delete Room Validation failures', () => { it('should handle empty roomIds array (no rooms deleted)', async () => { const response = await bulkDeleteRooms([]); expect(response.status).toBe(422); expect(response.body.error).toContain('Unprocessable Entity'); expect(JSON.stringify(response.body.details)).toContain( 'At least one valid roomId is required after sanitization' ); }); it('should fail when roomIds contains an ID that becomes empty after sanitization', async () => { const response = await bulkDeleteRooms([',,,,']); expect(response.status).toBe(422); expect(response.body.error).toContain('Unprocessable Entity'); expect(JSON.stringify(response.body.details)).toContain( 'At least one valid roomId is required after sanitization' ); }); it('should validate roomIds and return 422 when all are invalid', async () => { const response = await bulkDeleteRooms(['!!@##$', '!!@##$', ',', '.,-------}{ยก$#<+']); expect(response.status).toBe(422); expect(response.body.error).toContain('Unprocessable Entity'); expect(JSON.stringify(response.body.details)).toContain( 'At least one valid roomId is required after sanitization' ); }); }); });