diff --git a/meet-ce/backend/tests/helpers/test-scenarios.ts b/meet-ce/backend/tests/helpers/test-scenarios.ts index a5d41b40..58986716 100644 --- a/meet-ce/backend/tests/helpers/test-scenarios.ts +++ b/meet-ce/backend/tests/helpers/test-scenarios.ts @@ -96,9 +96,10 @@ export const setupMultiRoomTestContext = async ( export const setupSingleRoomWithRecording = async ( stopRecordingCond = false, - stopDelay?: StringValue + stopDelay?: StringValue, + roomName = 'TEST_ROOM' ): Promise => { - const roomData = await setupSingleRoom(true, 'TEST_ROOM'); + const roomData = await setupSingleRoom(true, roomName); const response = await startRecording(roomData.room.roomId, roomData.moderatorToken); expectValidStartRecordingResponse(response, roomData.room.roomId, roomData.room.roomName); roomData.recordingId = response.body.recordingId; diff --git a/meet-ce/backend/tests/integration/api/recordings/get-recordings.test.ts b/meet-ce/backend/tests/integration/api/recordings/get-recordings.test.ts index 5e62de73..2566cbd9 100644 --- a/meet-ce/backend/tests/integration/api/recordings/get-recordings.test.ts +++ b/meet-ce/backend/tests/integration/api/recordings/get-recordings.test.ts @@ -13,14 +13,11 @@ import { generateRoomMemberToken, getAllRecordings, getAllRecordingsFromRoom, - startTestServer + startTestServer, + stopRecording } from '../../../helpers/request-helpers.js'; -import { - RoomData, - setupMultiRecordingsTestContext, - setupSingleRoomWithRecording, - TestContext -} from '../../../helpers/test-scenarios.js'; +import { setupMultiRecordingsTestContext, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios.js'; +import { RoomData, TestContext } from '../../../interfaces/scenarios.js'; describe('Recordings API Tests', () => { let context: TestContext | null = null; @@ -81,6 +78,23 @@ describe('Recordings API Tests', () => { expect(response.body.recordings[0].roomId).toBe(room.roomId); }); + it('should filter recordings by status', async () => { + // Create recordings with different statuses + const [roomData] = await Promise.all([ + setupSingleRoomWithRecording(false), // Active + setupSingleRoomWithRecording(true) // Complete + ]); + + const response = await getAllRecordings({ status: MeetRecordingStatus.COMPLETE }); + expectSuccessListRecordingResponse(response, 1, false, false); + + const recordings = response.body.recordings; + expect(recordings[0].status).toBe(MeetRecordingStatus.COMPLETE); + + // Stop the active recording to clean up + await stopRecording(roomData.recordingId!, roomData.moderatorToken); + }); + it('should return recordings with fields filter applied', async () => { context = await setupMultiRecordingsTestContext(2, 2, 2); ({ room } = context.getRoomByIndex(0)!); @@ -147,6 +161,130 @@ describe('Recordings API Tests', () => { }); }); + describe('List Recordings Sorting', () => { + let roomDataA: RoomData; + let roomDataB: RoomData; + let roomDataC: RoomData; + + beforeAll(async () => { + // Create a single set of recordings that can be used by all sorting tests + // Created sequentially to ensure known creation order for startDate sorting + // With specific names for roomName sorting + // With different durations for duration/size sorting + roomDataA = await setupSingleRoomWithRecording(true, '1s', 'Room A'); + roomDataB = await setupSingleRoomWithRecording(true, '2s', 'Room B'); + roomDataC = await setupSingleRoomWithRecording(false, undefined, 'Room C'); + }); + + afterAll(async () => { + // Stop the active recording + await stopRecording(roomDataC.recordingId!, roomDataC.moderatorToken); + + // Disconnect participants and clean up + await disconnectFakeParticipants(); + await Promise.all([deleteAllRooms(), deleteAllRecordings()]); + }); + + it('should sort recordings by startDate ascending and descending', async () => { + // Test ascending + let response = await getAllRecordings({ sortField: 'startDate', sortOrder: 'asc' }); + let recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + expect(recordings[0].recordingId).toBe(roomDataA.recordingId); + expect(recordings[1].recordingId).toBe(roomDataB.recordingId); + expect(recordings[2].recordingId).toBe(roomDataC.recordingId); + + // Test descending + response = await getAllRecordings({ sortField: 'startDate', sortOrder: 'desc' }); + recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + expect(recordings).toHaveLength(3); + expect(recordings[0].recordingId).toBe(roomDataC.recordingId); + expect(recordings[1].recordingId).toBe(roomDataB.recordingId); + expect(recordings[2].recordingId).toBe(roomDataA.recordingId); + }); + + it('should sort recordings by roomName ascending and descending', async () => { + // Test ascending + let response = await getAllRecordings({ sortField: 'roomName', sortOrder: 'asc' }); + let recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + expect(recordings).toHaveLength(3); + expect(recordings[0].roomName).toBe(roomDataA.room.roomName); + expect(recordings[1].roomName).toBe(roomDataB.room.roomName); + expect(recordings[2].roomName).toBe(roomDataC.room.roomName); + + // Test descending + response = await getAllRecordings({ sortField: 'roomName', sortOrder: 'desc' }); + recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + expect(recordings).toHaveLength(3); + expect(recordings[0].roomName).toBe(roomDataC.room.roomName); + expect(recordings[1].roomName).toBe(roomDataB.room.roomName); + expect(recordings[2].roomName).toBe(roomDataA.room.roomName); + }); + + it('should sort recordings by duration ascending and descending', async () => { + // Test ascending + let response = await getAllRecordings({ sortField: 'duration', sortOrder: 'asc' }); + let recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + // The active recording has no duration, so it should appear first + expect(recordings[0].recordingId).toBe(roomDataC.recordingId); + expect(recordings[0].duration).toBeUndefined(); + + // Then the completed recordings in ascending duration order + expect(recordings[1].recordingId).toBe(roomDataA.recordingId); + expect(recordings[2].recordingId).toBe(roomDataB.recordingId); + + // Test descending + response = await getAllRecordings({ sortField: 'duration', sortOrder: 'desc' }); + recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + // Completed recordings in descending duration order + expect(recordings[0].recordingId).toBe(roomDataB.recordingId); + expect(recordings[1].recordingId).toBe(roomDataA.recordingId); + + // The active recording has no duration, so it should appear last + expect(recordings[2].recordingId).toBe(roomDataC.recordingId); + expect(recordings[2].duration).toBeUndefined(); + }); + + it('should sort recordings by size ascending and descending', async () => { + // Test ascending + let response = await getAllRecordings({ sortField: 'size', sortOrder: 'asc' }); + let recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + // The active recording has no size, so it should appear first + expect(recordings[0].recordingId).toBe(roomDataC.recordingId); + expect(recordings[0].size).toBeUndefined(); + + // Then the completed recordings in ascending size order + expect(recordings[1].recordingId).toBe(roomDataA.recordingId); + expect(recordings[2].recordingId).toBe(roomDataB.recordingId); + + // Test descending + response = await getAllRecordings({ sortField: 'size', sortOrder: 'desc' }); + recordings = response.body.recordings; + expectSuccessListRecordingResponse(response, 3, false, false); + + // Completed recordings in descending size order + expect(recordings[0].recordingId).toBe(roomDataB.recordingId); + expect(recordings[1].recordingId).toBe(roomDataA.recordingId); + + // The active recording has no size, so it should appear last + expect(recordings[2].recordingId).toBe(roomDataC.recordingId); + expect(recordings[2].size).toBeUndefined(); + }); + }); + describe('List Recordings Validation', () => { it('should fail when maxItems is not a number', async () => { const response = await getAllRecordings({ maxItems: 'not-a-number' }); @@ -167,5 +305,20 @@ describe('Recordings API Tests', () => { const response = await getAllRecordings({ fields: { invalid: 'object' } }); expectValidationError(response, 'fields', 'Expected string'); }); + + it('should fail when sortField is invalid', async () => { + const response = await getAllRecordings({ sortField: 'invalidField' }); + expectValidationError(response, 'sortField', 'Invalid enum value'); + }); + + it('should fail when sortOrder is invalid', async () => { + const response = await getAllRecordings({ sortOrder: 'invalid' }); + expectValidationError(response, 'sortOrder', 'Invalid enum value'); + }); + + it('should fail when status is invalid', async () => { + const response = await getAllRecordings({ status: 'invalid_status' }); + expectValidationError(response, 'status', 'Invalid enum value'); + }); }); }); 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 b22851b0..2003708d 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 @@ -1,6 +1,6 @@ -import { afterEach, beforeAll, describe, it } from '@jest/globals'; +import { afterEach, beforeAll, describe, expect, it } from '@jest/globals'; +import { MeetRoom, MeetRoomStatus } from '@openvidu-meet/typings'; import ms from 'ms'; -import { MeetRoom } from '@openvidu-meet/typings'; import { expectSuccessRoomsResponse, expectValidationError, @@ -8,6 +8,7 @@ import { expectValidRoomWithFields } from '../../../helpers/assertion-helpers.js'; import { createRoom, deleteAllRooms, getRooms, startTestServer } from '../../../helpers/request-helpers.js'; +import { setupSingleRoom } from '../../../helpers/test-scenarios.js'; describe('Room API Tests', () => { const validAutoDeletionDate = Date.now() + ms('2h'); @@ -68,6 +69,17 @@ describe('Room API Tests', () => { expectValidRoom(rooms[0], 'test-room'); }); + it('should return a list of rooms applying status filter', async () => { + await setupSingleRoom(true); // Active meeting + await setupSingleRoom(false); // Open + + const response = await getRooms({ status: MeetRoomStatus.ACTIVE_MEETING }); + const { rooms } = response.body; + + expectSuccessRoomsResponse(response, 1, 10, false, false); + expect(rooms[0].status).toBe(MeetRoomStatus.ACTIVE_MEETING); + }); + it('should return a list of rooms with pagination', async () => { // Create rooms sequentially to ensure different creation dates for (let i = 0; i < 6; i++) { @@ -106,6 +118,82 @@ describe('Room API Tests', () => { expectSuccessRoomsResponse(response, 0, 12, false, false); }); + + it('should sort rooms by roomName ascending and descending', async () => { + await createRoom({ roomName: 'zebra-room' }); + await createRoom({ roomName: 'alpha-room' }); + await createRoom({ roomName: 'beta-room' }); + + // Test ascending + let response = await getRooms({ sortField: 'roomName', sortOrder: 'asc' }); + let rooms = response.body.rooms; + + expectSuccessRoomsResponse(response, 3, 10, false, false); + expectValidRoom(rooms[0], 'alpha-room'); + expectValidRoom(rooms[1], 'beta-room'); + expectValidRoom(rooms[2], 'zebra-room'); + + // Test descending + response = await getRooms({ sortField: 'roomName', sortOrder: 'desc' }); + rooms = response.body.rooms; + + expectSuccessRoomsResponse(response, 3, 10, false, false); + expectValidRoom(rooms[0], 'zebra-room'); + expectValidRoom(rooms[1], 'beta-room'); + expectValidRoom(rooms[2], 'alpha-room'); + }); + + it('should sort rooms by creationDate ascending and descending', async () => { + const room1 = await createRoom({ roomName: 'first-room' }); + const room2 = await createRoom({ roomName: 'second-room' }); + const room3 = await createRoom({ roomName: 'third-room' }); + + // Test ascending + let response = await getRooms({ sortField: 'creationDate', sortOrder: 'asc' }); + let rooms = response.body.rooms; + + expectSuccessRoomsResponse(response, 3, 10, false, false); + expectValidRoom(rooms[0], room1.roomName); + expectValidRoom(rooms[1], room2.roomName); + expectValidRoom(rooms[2], room3.roomName); + + // Test descending (default) + response = await getRooms({ sortField: 'creationDate', sortOrder: 'desc' }); + rooms = response.body.rooms; + + expectSuccessRoomsResponse(response, 3, 10, false, false); + expectValidRoom(rooms[0], room3.roomName); + expectValidRoom(rooms[1], room2.roomName); + expectValidRoom(rooms[2], room1.roomName); + }); + + it('should sort rooms by autoDeletionDate ascending and descending', async () => { + const now = Date.now(); + const date1 = now + ms('2h'); + const date2 = now + ms('3h'); + + await createRoom({ roomName: 'room-3h', autoDeletionDate: date2 }); + await createRoom({ roomName: 'room-2h', autoDeletionDate: date1 }); + await createRoom({ roomName: 'room-without-date' }); // Room without autoDeletionDate + + // Test ascending + let response = await getRooms({ sortField: 'autoDeletionDate', sortOrder: 'asc' }); + let rooms = response.body.rooms; + + expectSuccessRoomsResponse(response, 3, 10, false, false); + expectValidRoom(rooms[0], 'room-without-date', undefined, undefined, undefined); + expectValidRoom(rooms[1], 'room-2h', undefined, undefined, date1); + expectValidRoom(rooms[2], 'room-3h', undefined, undefined, date2); + + // Test descending + response = await getRooms({ sortField: 'autoDeletionDate', sortOrder: 'desc' }); + rooms = response.body.rooms; + + expectSuccessRoomsResponse(response, 3, 10, false, false); + expectValidRoom(rooms[0], 'room-3h', undefined, undefined, date2); + expectValidRoom(rooms[1], 'room-2h', undefined, undefined, date1); + expectValidRoom(rooms[2], 'room-without-date', undefined, undefined, undefined); + }); }); describe('List Room Validation failures', () => { @@ -128,5 +216,20 @@ describe('Room API Tests', () => { const response = await getRooms({ fields: { invalid: 'data' } }); expectValidationError(response, 'fields', 'Expected string'); }); + + it('should fail when sortField is invalid', async () => { + const response = await getRooms({ sortField: 'invalidField' }); + expectValidationError(response, 'sortField', 'Invalid enum value'); + }); + + it('should fail when sortOrder is invalid', async () => { + const response = await getRooms({ sortOrder: 'invalid' }); + expectValidationError(response, 'sortOrder', 'Invalid enum value'); + }); + + it('should fail when status is invalid', async () => { + const response = await getRooms({ status: 'invalid_status' }); + expectValidationError(response, 'status', 'Invalid enum value'); + }); }); });