import { afterAll, beforeAll, describe, expect, it } from '@jest/globals'; import { MeetUser, MeetUserRole } from '@openvidu-meet/typings'; import { MEET_ENV } from '../../../../src/environment.js'; import { expectValidationError } from '../../../helpers/assertion-helpers.js'; import { createUser, deleteAllUsers, getUsers, startTestServer } from '../../../helpers/request-helpers.js'; describe('Users API Tests', () => { beforeAll(async () => { await startTestServer(); // Create a timestamp to ensure unique IDs (max 6 digits to fit in 20 char limit) const ts = String(Date.now()).slice(-6); // Create users sequentially to have predictable registration order await createUser({ userId: `alice_${ts}`, name: 'Alice Anderson', password: 'password123', role: MeetUserRole.ADMIN }); await createUser({ userId: `bob_${ts}`, name: 'Bob Brown', password: 'password123', role: MeetUserRole.USER }); await createUser({ userId: `charlie_${ts}`, name: 'Charlie Clark', password: 'password123', role: MeetUserRole.ROOM_MEMBER }); await createUser({ userId: `diana_${ts}`, name: 'Diana Davis', password: 'password123', role: MeetUserRole.ADMIN }); await createUser({ userId: `eve_${ts}`, name: 'Eve Evans', password: 'password123', role: MeetUserRole.USER }); }); afterAll(async () => { await deleteAllUsers(); }); describe('Get Users Tests', () => { it('should successfully get all users without filters', async () => { const response = await getUsers(); expect(response.status).toBe(200); expect(response.body).toHaveProperty('users'); expect(Array.isArray(response.body.users)).toBe(true); // Root admin + 5 test users = 6 total expect(response.body.users.length).toBe(6); expect(response.body).toHaveProperty('pagination'); expect(response.body.pagination).toHaveProperty('isTruncated', false); }); it('should filter users by userId using partial match', async () => { const response = await getUsers({ userId: 'alice' }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(1); expect(response.body.users[0].userId).toContain('alice'); }); it('should filter users by userId case-insensitive', async () => { const response = await getUsers({ userId: 'ALICE' }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(1); expect(response.body.users[0].userId).toContain('alice'); }); it('should filter users by name using partial match', async () => { const response = await getUsers({ name: 'Anderson' }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(1); expect(response.body.users[0].name).toContain('Anderson'); }); it('should filter users by name case-insensitive', async () => { const response = await getUsers({ name: 'brown' }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(1); expect(response.body.users[0].name).toContain('Brown'); }); it('should filter root admin by userId', async () => { const response = await getUsers({ userId: MEET_ENV.INITIAL_ADMIN_USER }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(1); expect(response.body.users[0]).toHaveProperty('userId', MEET_ENV.INITIAL_ADMIN_USER); expect(response.body.users[0]).toHaveProperty('role', MeetUserRole.ADMIN); }); it('should filter users by role', async () => { const response = await getUsers({ role: MeetUserRole.ADMIN }); expect(response.status).toBe(200); // We created 2 admins + 1 root admin = 3 total expect(response.body.users).toHaveLength(3); response.body.users.forEach((user: MeetUser) => { expect(user).toHaveProperty('role', MeetUserRole.ADMIN); }); }); it('should return empty array when no users match filter', async () => { const response = await getUsers({ userId: 'nonexistent123xyz' }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(0); }); it('should respect maxItems parameter', async () => { const response = await getUsers({ maxItems: 2 }); expect(response.status).toBe(200); expect(response.body.users.length).toBe(2); expect(response.body.pagination).toHaveProperty('maxItems', 2); }); it('should limit maxItems to 100', async () => { const response = await getUsers({ maxItems: 150 }); expect(response.status).toBe(200); expect(response.body.pagination).toHaveProperty('maxItems', 100); }); it('should use default maxItems of 10 when not specified', async () => { const response = await getUsers(); expect(response.status).toBe(200); expect(response.body.pagination).toHaveProperty('maxItems', 10); }); it('should handle pagination with isTruncated flag', async () => { // Request only 3 users when we have 6 total const response = await getUsers({ maxItems: 3 }); expect(response.status).toBe(200); expect(response.body.users).toHaveLength(3); expect(response.body.pagination).toHaveProperty('isTruncated', true); expect(response.body.pagination).toHaveProperty('nextPageToken'); }); it('should support pagination with nextPageToken', async () => { // First page: 3 users const firstResponse = await getUsers({ maxItems: 3 }); expect(firstResponse.status).toBe(200); expect(firstResponse.body.users).toHaveLength(3); expect(firstResponse.body.pagination.isTruncated).toBe(true); // Second page: next 3 users const secondResponse = await getUsers({ maxItems: 3, nextPageToken: firstResponse.body.pagination.nextPageToken }); expect(secondResponse.status).toBe(200); expect(secondResponse.body.users).toHaveLength(3); expect(secondResponse.body.pagination.isTruncated).toBe(false); }); it('should sort users by registrationDate in descending order by default', async () => { const response = await getUsers(); expect(response.status).toBe(200); expect(response.body.users.length).toBe(6); // Eve was created last, should be first (most recent) expect(response.body.users[0].userId).toContain('eve'); // Root admin was created first, should be last (oldest) expect(response.body.users[5].userId).toBe('admin'); // Verify all dates are in descending order for (let i = 0; i < response.body.users.length - 1; i++) { expect(response.body.users[i].registrationDate).toBeGreaterThanOrEqual( response.body.users[i + 1].registrationDate ); } }); it('should sort users by registrationDate in ascending order', async () => { const response = await getUsers({ sortField: 'registrationDate', sortOrder: 'asc' }); expect(response.status).toBe(200); expect(response.body.users.length).toBe(6); // Root admin was created first, should be first (oldest) expect(response.body.users[0].userId).toBe('admin'); // Eve was created last, should be last (most recent) expect(response.body.users[5].userId).toContain('eve'); // Verify all dates are in ascending order for (let i = 0; i < response.body.users.length - 1; i++) { expect(response.body.users[i].registrationDate).toBeLessThanOrEqual( response.body.users[i + 1].registrationDate ); } }); it('should sort users by name in descending order', async () => { const response = await getUsers({ sortField: 'name', sortOrder: 'desc' }); expect(response.status).toBe(200); expect(response.body.users.length).toBe(6); // Verify names are in reverse alphabetical order (case-insensitive) for (let i = 0; i < response.body.users.length - 1; i++) { const currentName = response.body.users[i].name.toLowerCase(); const nextName = response.body.users[i + 1].name.toLowerCase(); expect(currentName.localeCompare(nextName)).toBeGreaterThanOrEqual(0); } }); it('should sort users by name in ascending order', async () => { const response = await getUsers({ sortField: 'name', sortOrder: 'asc' }); expect(response.status).toBe(200); expect(response.body.users.length).toBe(6); // Verify names are in alphabetical order (case-insensitive) for (let i = 0; i < response.body.users.length - 1; i++) { const currentName = response.body.users[i].name.toLowerCase(); const nextName = response.body.users[i + 1].name.toLowerCase(); expect(currentName.localeCompare(nextName)).toBeLessThanOrEqual(0); } }); it('should not expose sensitive fields in user objects', async () => { const response = await getUsers({ maxItems: 3 }); expect(response.status).toBe(200); response.body.users.forEach((user: MeetUser) => { expect(user).not.toHaveProperty('passwordHash'); expect(user).not.toHaveProperty('mustChangePassword'); expect(user).toHaveProperty('userId'); expect(user).toHaveProperty('name'); expect(user).toHaveProperty('role'); expect(user).toHaveProperty('registrationDate'); }); }); }); describe('Get Users Validation Tests', () => { it('should fail when maxItems is zero', async () => { const response = await getUsers({ maxItems: 0 }); expectValidationError(response, 'maxItems', 'must be a positive number'); }); it('should fail when maxItems is negative', async () => { const response = await getUsers({ maxItems: -5 }); expectValidationError(response, 'maxItems', 'must be a positive number'); }); it('should fail when sortField is invalid', async () => { const response = await getUsers({ sortField: 'userId' }); expectValidationError(response, 'sortField', 'Invalid enum value'); }); it('should fail when sortOrder is invalid', async () => { const response = await getUsers({ sortOrder: 'invalid' }); expectValidationError(response, 'sortOrder', 'Invalid enum value'); }); }); });