test: Add integration tests for recordings API with validation and pagination checks

This commit is contained in:
Carlos Santos 2025-04-25 13:54:30 +02:00
parent 68f809c690
commit 1a128dd36c
2 changed files with 149 additions and 4 deletions

View File

@ -80,12 +80,16 @@ const BulkDeleteRecordingsSchema = z.object({
const GetRecordingsFiltersSchema: z.ZodType<MeetRecordingFilters> = z.object({
maxItems: z.coerce
.number()
.int()
.optional()
.transform((val = 10) => (val > 100 ? 100 : val))
.positive('maxItems must be a positive number')
.transform((val) => {
// Convert the value to a number
const intVal = Math.floor(val);
// Ensure it's not greater than 100
return intVal > 100 ? 100 : intVal;
})
.default(10),
// status: z.string().optional(),
roomId: z.string().optional(),
roomId: nonEmptySanitizedRoomId('roomId').optional(),
nextPageToken: z.string().optional(),
fields: z.string().optional()
});

View File

@ -0,0 +1,141 @@
import { describe, it, expect, beforeAll, afterEach, afterAll } from '@jest/globals';
import {
deleteAllRecordings,
deleteAllRooms,
disconnectFakeParticipants,
getAllRecordings,
startTestServer
} from '../../../utils/helpers.js';
import {
expectValidationError,
expectSuccessListRecordingResponse,
expectValidRecordingWithFields,
expectValidRecording
} from '../../../utils/assertion-helpers.js';
import { RoomData, setupMultiRecordingsTestContext, TestContext } from '../../../utils/test-scenarios.js';
import { MeetRoom } from '../../../../src/typings/ce/room.js';
import { MeetRecordingInfo, MeetRecordingStatus } from '../../../../src/typings/ce/recording.model.js';
describe('Recordings API Tests', () => {
let context: TestContext | null = null;
let room: MeetRoom;
beforeAll(async () => {
startTestServer();
await deleteAllRecordings();
});
describe('List Recordings Tests', () => {
afterEach(async () => {
await deleteAllRecordings();
});
afterAll(async () => {
await disconnectFakeParticipants();
await deleteAllRooms();
context = null;
});
it('should return an empty list of recordings when none exist', async () => {
const response = await getAllRecordings();
expect(response.status).toBe(200);
expectSuccessListRecordingResponse(response, 0, false, false);
});
it('should return a list of recordings', async () => {
context = await setupMultiRecordingsTestContext(1, 1, 1, '0s');
({ room } = context.getRoomByIndex(0)!);
const response = await getAllRecordings();
expectSuccessListRecordingResponse(response, 1, false, false);
});
it('should filter recordings by roomId', async () => {
context = await setupMultiRecordingsTestContext(2, 2, 2, '0s');
({ room } = context.getRoomByIndex(0)!);
const response = await getAllRecordings({ roomId: room.roomId });
expectSuccessListRecordingResponse(response, 1, false, false);
expect(response.body.recordings[0].roomId).toBe(room.roomId);
});
it('should return recordings with fields filter applied', async () => {
context = await setupMultiRecordingsTestContext(2, 2, 2, '0s');
({ room } = context.getRoomByIndex(0)!);
const response = await getAllRecordings({ fields: 'roomId,recordingId' });
expectSuccessListRecordingResponse(response, 2, false, false);
context.rooms.forEach((roomData: RoomData) => {
const room = roomData.room;
const recording = response.body.recordings.find(
(recording: MeetRecordingInfo) => recording.roomId === room.roomId
);
expect(recording).toBeDefined();
expectValidRecordingWithFields(recording, ['roomId', 'recordingId']);
expect(recording).toHaveProperty('roomId', room.roomId);
expect(recording.recordingId).toContain(room.roomId);
});
});
it('should return recordings with pagination', async () => {
context = await setupMultiRecordingsTestContext(6, 6, 6, '0s');
const rooms = context.rooms;
const response = await getAllRecordings({ maxItems: 3 });
expectSuccessListRecordingResponse(response, 3, true, true, 3);
response.body.recordings.forEach((recording: MeetRecordingInfo, i: number) => {
expectValidRecording(
recording,
rooms[i].recordingId!,
rooms[i].room.roomId,
MeetRecordingStatus.COMPLETE
);
});
const nextPageToken = response.body.pagination.nextPageToken;
const nextResponse = await getAllRecordings({ maxItems: 3, nextPageToken });
expectSuccessListRecordingResponse(nextResponse, 3, false, false, 3);
nextResponse.body.recordings.forEach((recording: MeetRecordingInfo, i: number) => {
expectValidRecording(
recording,
rooms[3 + i].recordingId!,
rooms[3 + i].room.roomId,
MeetRecordingStatus.COMPLETE
);
});
});
it('should cap maxItems to the maximum allowed (100)', async () => {
context = await setupMultiRecordingsTestContext(1, 1, 1, '0s');
const response = await getAllRecordings({ maxItems: 101 });
expectSuccessListRecordingResponse(response, 1, false, false, 100);
});
it('should coerce a floating point number to integer for maxItems', async () => {
context = await setupMultiRecordingsTestContext(1, 1, 1, '0s');
const response = await getAllRecordings({ maxItems: 3.5 });
expectSuccessListRecordingResponse(response, 1, false, false, 3);
});
});
describe('List Recordings Validation', () => {
it('should fail when maxItems is not a number', async () => {
const response = await getAllRecordings({ maxItems: 'not-a-number' });
expectValidationError(response, 'maxItems', 'Expected number');
});
it('should fail when maxItems is negative', async () => {
const response = await getAllRecordings({ maxItems: -5 });
expectValidationError(response, 'maxItems', 'must be a positive number');
});
it('should fail when maxItems is zero', async () => {
const response = await getAllRecordings({ maxItems: 0 });
expectValidationError(response, 'maxItems', 'must be a positive number');
});
it('should fail when fields is not a string', async () => {
const response = await getAllRecordings({ fields: { invalid: 'object' } });
expectValidationError(response, 'fields', 'Expected string');
});
});
});