From 256236111ee83cbc95c69b73d2fcc8661d172f97 Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Fri, 25 Apr 2025 16:36:28 +0200 Subject: [PATCH] test: Add integration tests for stopping recordings with validation checks --- .../api/recordings/stop-recording.test.ts | 99 +++++++++++++++++++ backend/tests/utils/assertion-helpers.ts | 9 +- 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 backend/tests/integration/api/recordings/stop-recording.test.ts diff --git a/backend/tests/integration/api/recordings/stop-recording.test.ts b/backend/tests/integration/api/recordings/stop-recording.test.ts new file mode 100644 index 0000000..3476616 --- /dev/null +++ b/backend/tests/integration/api/recordings/stop-recording.test.ts @@ -0,0 +1,99 @@ +import { describe, it, expect, beforeAll, afterAll } from '@jest/globals'; +import { expectValidStopRecordingResponse, expectErrorResponse } from '../../../utils/assertion-helpers'; +import { + startRecording, + disconnectFakeParticipants, + stopAllRecordings, + stopRecording, + deleteAllRecordings, + deleteAllRooms, + startTestServer +} from '../../../utils/helpers'; +import { MeetRoom } from '../../../../src/typings/ce'; +import { setupMultiRoomTestContext, TestContext } from '../../../utils/test-scenarios'; + +describe('Recording API Tests', () => { + let context: TestContext | null = null; + let room: MeetRoom, moderatorCookie: string; + + beforeAll(async () => { + startTestServer(); + }); + afterAll(async () => { + await stopAllRecordings(moderatorCookie); + await disconnectFakeParticipants(); + await deleteAllRooms(); + await deleteAllRecordings(); + }); + + describe('Stop Recording Tests', () => { + let recordingId: string; + beforeAll(async () => { + // Create a room and join a participant + context = await setupMultiRoomTestContext(1, true); + ({ room, moderatorCookie } = context.getRoomByIndex(0)!); + const response = await startRecording(room.roomId, moderatorCookie); + recordingId = response.body.recordingId; + }); + + afterAll(async () => { + await disconnectFakeParticipants(); + await stopAllRecordings(moderatorCookie); + await deleteAllRooms(); + await deleteAllRecordings(); + context = null; + }); + + it('should stop an active recording and return 202', async () => { + const response = await stopRecording(recordingId, moderatorCookie); + expectValidStopRecordingResponse(response, recordingId, room.roomId); + }); + + it('should stop multiple recordings in parallel', async () => { + const context = await setupMultiRoomTestContext(2, true); + const roomDataA = context.getRoomByIndex(0); + const roomDataB = context.getRoomByIndex(1); + const responseA = await startRecording(roomDataA!.room.roomId, roomDataA?.moderatorCookie); + const responseB = await startRecording(roomDataB!.room.roomId, roomDataB?.moderatorCookie); + const recordingIdA = responseA.body.recordingId; + const recordingIdB = responseB.body.recordingId; + const stopResponseA = await stopRecording(recordingIdA, roomDataA?.moderatorCookie); + expectValidStopRecordingResponse(stopResponseA, recordingIdA, roomDataA!.room.roomId); + const stopResponseB = await stopRecording(recordingIdB, roomDataB?.moderatorCookie); + expectValidStopRecordingResponse(stopResponseB, recordingIdB, roomDataB!.room.roomId); + }); + + describe('Stop Recording Validation failures', () => { + it('should return 404 when recordingId does not exist', async () => { + const response = await stopRecording(`${room.roomId}--EG_123--444`, moderatorCookie); + expect(response.status).toBe(404); + expect(response.body.name).toBe('Recording Error'); + expect(response.body.message).toContain('not found'); + }); + + it('should return 400 when recording is already stopped', async () => { + // First stop the recording + await stopRecording(recordingId, moderatorCookie); + + // Try to stop it again + const response = await stopRecording(recordingId, moderatorCookie); + + console.log('Response:', response.body); + expectErrorResponse(response, 409, '', `Recording '${recordingId}' is already stopped`); + }); + + it('should return 404 when recordingId is not in the correct format', async () => { + const response = await stopRecording('invalid-recording-id', moderatorCookie); + expect(response.status).toBe(422); + expect(response.body.error).toBe('Unprocessable Entity'); + expect(response.body.message).toContain('Invalid request'); + expect(response.body.details).toStrictEqual([ + { + field: 'recordingId', + message: 'recordingId does not follow the expected format' + } + ]); + }); + }); + }); +}); diff --git a/backend/tests/utils/assertion-helpers.ts b/backend/tests/utils/assertion-helpers.ts index aef3b74..5f3d6b0 100644 --- a/backend/tests/utils/assertion-helpers.ts +++ b/backend/tests/utils/assertion-helpers.ts @@ -10,7 +10,7 @@ import { const RECORDINGS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/recordings`; -const expectErrorResponse = ( +export const expectErrorResponse = ( response: any, status = 422, error = 'Unprocessable Entity', @@ -18,7 +18,10 @@ const expectErrorResponse = ( details?: Array<{ field?: string; message: string }> ) => { expect(response.status).toBe(status); - expect(response.body).toMatchObject({ error, message }); + expect(response.body).toMatchObject({ + ...(error ? { error } : {}), + ...(message ? { message } : {}) + }); if (details === undefined) { expect(response.body.details).toBeUndefined(); @@ -207,7 +210,7 @@ export const expectValidStopRecordingResponse = (response: any, recordingId: str expect(response.status).toBe(202); expect(response.body).toBeDefined(); expect(response.body).toHaveProperty('recordingId', recordingId); - expect(response.body).toHaveProperty('status', 'ENDING'); + expect([MeetRecordingStatus.COMPLETE, MeetRecordingStatus.ENDING]).toContain(response.body.status); expect(response.body).toHaveProperty('roomId', roomId); expect(response.body).toHaveProperty('filename'); expect(response.body).toHaveProperty('startDate');