test: enhance change password and user profile tests with new scenarios and validations

This commit is contained in:
juancarmore 2026-01-30 17:27:21 +01:00
parent 54c2c79ccb
commit c561cf9bcd
3 changed files with 270 additions and 82 deletions

View File

@ -10,9 +10,9 @@ import {
} from '../models/error.model.js';
import { LoggerService } from '../services/logger.service.js';
import { RequestSessionService } from '../services/request-session.service.js';
import { TokenService } from '../services/token.service.js';
import { UserService } from '../services/user.service.js';
import { getBaseUrl } from '../utils/url.utils.js';
import { TokenService } from '../services/token.service.js';
export const createUser = async (req: Request, res: Response) => {
const userOptions = req.body as MeetUserOptions;
@ -76,47 +76,6 @@ export const getUser = async (req: Request, res: Response) => {
}
};
export const deleteUser = async (req: Request, res: Response) => {
const { userId } = req.params;
const logger = container.get(LoggerService);
logger.verbose(`Deleting user with ID '${userId}'`);
try {
const userService = container.get(UserService);
await userService.deleteUser(userId);
return res.status(200).json({ message: `User '${userId}' deleted successfully` });
} catch (error) {
handleError(res, error, 'deleting user');
}
};
export const bulkDeleteUsers = async (req: Request, res: Response) => {
const { userIds } = req.query as { userIds: string[] };
const logger = container.get(LoggerService);
logger.verbose(`Deleting users: ${userIds}`);
try {
const userService = container.get(UserService);
const { deleted, failed } = await userService.bulkDeleteUsers(userIds);
// All users were successfully deleted
if (deleted.length > 0 && failed.length === 0) {
return res.status(200).json({ message: 'All users deleted successfully', deleted });
}
// Some or all users could not be deleted
return res.status(400).json({
message: `${failed.length} user(s) could not be deleted`,
deleted,
failed
});
} catch (error) {
handleError(res, error, 'deleting users');
}
};
export const getMe = (_req: Request, res: Response) => {
const requestSessionService = container.get(RequestSessionService);
const user = requestSessionService.getAuthenticatedUser();
@ -150,26 +109,6 @@ export const resetUserPassword = async (req: Request, res: Response) => {
}
};
export const updateUserRole = async (req: Request, res: Response) => {
const { userId } = req.params;
const { role } = req.body as { role: MeetUserRole };
const logger = container.get(LoggerService);
logger.verbose(`Admin updating role for user '${userId}' to '${role}'`);
try {
const userService = container.get(UserService);
const user = await userService.changeUserRole(userId, role);
return res.status(200).json({
message: `Role for user '${userId}' updated successfully to '${role}'`,
user: userService.convertToDTO(user)
});
} catch (error) {
handleError(res, error, 'updating user role');
}
};
export const changePassword = async (req: Request, res: Response) => {
const requestSessionService = container.get(RequestSessionService);
const user = requestSessionService.getAuthenticatedUser();
@ -210,3 +149,64 @@ export const changePassword = async (req: Request, res: Response) => {
handleError(res, error, 'changing password');
}
};
export const updateUserRole = async (req: Request, res: Response) => {
const { userId } = req.params;
const { role } = req.body as { role: MeetUserRole };
const logger = container.get(LoggerService);
logger.verbose(`Admin updating role for user '${userId}' to '${role}'`);
try {
const userService = container.get(UserService);
const user = await userService.changeUserRole(userId, role);
return res.status(200).json({
message: `Role for user '${userId}' updated successfully to '${role}'`,
user: userService.convertToDTO(user)
});
} catch (error) {
handleError(res, error, 'updating user role');
}
};
export const deleteUser = async (req: Request, res: Response) => {
const { userId } = req.params;
const logger = container.get(LoggerService);
logger.verbose(`Deleting user with ID '${userId}'`);
try {
const userService = container.get(UserService);
await userService.deleteUser(userId);
return res.status(200).json({ message: `User '${userId}' deleted successfully` });
} catch (error) {
handleError(res, error, 'deleting user');
}
};
export const bulkDeleteUsers = async (req: Request, res: Response) => {
const { userIds } = req.query as { userIds: string[] };
const logger = container.get(LoggerService);
logger.verbose(`Deleting users: ${userIds}`);
try {
const userService = container.get(UserService);
const { deleted, failed } = await userService.bulkDeleteUsers(userIds);
// All users were successfully deleted
if (deleted.length > 0 && failed.length === 0) {
return res.status(200).json({ message: 'All users deleted successfully', deleted });
}
// Some or all users could not be deleted
return res.status(400).json({
message: `${failed.length} user(s) could not be deleted`,
deleted,
failed
});
} catch (error) {
handleError(res, error, 'deleting users');
}
};

View File

@ -1,35 +1,175 @@
import { beforeAll, describe, expect, it } from '@jest/globals';
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
import { MeetUserRole } from '@openvidu-meet/typings';
import { MEET_ENV } from '../../../../src/environment.js';
import { expectValidationError } from '../../../helpers/assertion-helpers.js';
import { changePassword, loginAdminUser, startTestServer } from '../../../helpers/request-helpers.js';
import {
changePassword,
changePasswordReq,
createRoom,
createUser,
deleteAllRooms,
deleteAllUsers,
loginReq,
loginRootAdmin,
loginUser,
refreshTokenReq,
startTestServer
} from '../../../helpers/request-helpers.js';
import { setupUser } from '../../../helpers/test-scenarios.js';
describe('Users API Tests', () => {
let adminAccessToken: string;
let rootAdminAccessToken: string;
beforeAll(async () => {
await startTestServer();
adminAccessToken = await loginAdminUser();
({ accessToken: rootAdminAccessToken } = await loginRootAdmin());
});
afterAll(async () => {
await deleteAllRooms();
await deleteAllUsers();
});
describe('Change Password Tests', () => {
it('should successfully change password', async () => {
it('should successfully change root admin password', async () => {
const newPassword = 'newpassword123';
const response = await changePassword(MEET_ENV.INITIAL_ADMIN_PASSWORD, newPassword, adminAccessToken);
const response = await changePasswordReq(
{ currentPassword: MEET_ENV.INITIAL_ADMIN_PASSWORD, newPassword },
rootAdminAccessToken
);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('message');
expect(response.body.message).toContain('changed successfully');
expect(response.body).not.toHaveProperty('accessToken');
expect(response.body).not.toHaveProperty('refreshToken');
// Reset password
await changePassword(newPassword, MEET_ENV.INITIAL_ADMIN_PASSWORD, adminAccessToken);
// Reset password back
await changePassword(newPassword, MEET_ENV.INITIAL_ADMIN_PASSWORD, rootAdminAccessToken);
});
it('should successfully login with new password after change', async () => {
const userId = MEET_ENV.INITIAL_ADMIN_USER;
const initialPassword = MEET_ENV.INITIAL_ADMIN_PASSWORD;
const newPassword = 'newpassword123';
// Change password
const changeResponse = await changePasswordReq(
{ currentPassword: initialPassword, newPassword },
rootAdminAccessToken
);
expect(changeResponse.status).toBe(200);
// Verify old password no longer works
const loginOldResponse = await loginReq({
userId,
password: initialPassword
});
expect(loginOldResponse.status).toBe(404);
// Verify new password works
const loginResponse = await loginReq({
userId,
password: newPassword
});
expect(loginResponse.status).toBe(200);
// Reset password back
await changePassword(newPassword, initialPassword, rootAdminAccessToken);
});
it('should successfully change password and return new tokens when mustChangePassword is true', async () => {
const userId = `user_${Date.now()}`;
const initialPassword = 'password123';
const newPassword = 'NewPassword123!';
// Create user (when created, this user is set to require password change)
const createResponse = await createUser({
userId,
name: 'Test User',
password: initialPassword,
role: MeetUserRole.USER
});
expect(createResponse.status).toBe(201);
// Login to get temporary token
const { accessToken: accessTokenTmp } = await loginUser(userId, initialPassword);
// Change password
const response = await changePasswordReq({ currentPassword: initialPassword, newPassword }, accessTokenTmp);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('message');
expect(response.body.message).toContain('changed successfully');
expect(response.body).toHaveProperty('accessToken');
expect(response.body).toHaveProperty('refreshToken');
const accessToken = response.body.accessToken;
const refreshToken = response.body.refreshToken;
// Verify new access token work
await createRoom({}, `Bearer ${accessToken}`);
// Verify new refresh token work
const refreshResponse = await refreshTokenReq(`Bearer ${refreshToken}`);
expect(refreshResponse.status).toBe(200);
});
it('should successfully change password for regular user without returning tokens', async () => {
const userData = await setupUser({
userId: `user_${Date.now()}`,
name: 'Regular User',
password: 'password123',
role: MeetUserRole.USER
});
// Change password
const response = await changePasswordReq(
{ currentPassword: userData.password, newPassword: 'newpassword123' },
userData.accessToken
);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('message');
expect(response.body.message).toContain('changed successfully');
expect(response.body).not.toHaveProperty('accessToken');
expect(response.body).not.toHaveProperty('refreshToken');
});
it('should fail when current password is incorrect', async () => {
const response = await changePassword('wrongpassword', 'newpassword123', adminAccessToken);
const response = await changePasswordReq(
{ currentPassword: 'wrongpassword', newPassword: 'newpassword123' },
rootAdminAccessToken
);
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('message', 'Invalid current password');
expect(response.body).toHaveProperty('message');
expect(response.body.message).toContain('Invalid current password');
});
});
describe('Change Password Validation Tests', () => {
it('should fail when new password is too short', async () => {
const response = await changePasswordReq(
{ currentPassword: MEET_ENV.INITIAL_ADMIN_PASSWORD, newPassword: '1234' },
rootAdminAccessToken
);
expectValidationError(response, 'newPassword', 'New password must be at least 5 characters long');
});
it('should fail when new password is not 5 characters long', async () => {
const response = await changePassword(MEET_ENV.INITIAL_ADMIN_PASSWORD, '1234', adminAccessToken);
expectValidationError(response, 'newPassword', 'New password must be at least 5 characters long');
it('should fail when currentPassword is missing', async () => {
const response = await changePasswordReq(
{ newPassword: 'newpassword123' } as { currentPassword: string; newPassword: string },
rootAdminAccessToken
);
expectValidationError(response, 'currentPassword', 'Required');
});
it('should fail when newPassword is missing', async () => {
const response = await changePasswordReq(
{ currentPassword: MEET_ENV.INITIAL_ADMIN_PASSWORD } as {
currentPassword: string;
newPassword: string;
},
rootAdminAccessToken
);
expectValidationError(response, 'newPassword', 'Required');
});
});
});

View File

@ -1,22 +1,70 @@
import { beforeAll, describe, expect, it } from '@jest/globals';
import { getMe, loginAdminUser, startTestServer } from '../../../helpers/request-helpers.js';
import { MeetUserRole } from '@openvidu-meet/typings';
import { MEET_ENV } from '../../../../src/environment.js';
import { deleteAllUsers, getMe, loginRootAdmin, startTestServer } from '../../../helpers/request-helpers.js';
import { setupTestUsers } from '../../../helpers/test-scenarios.js';
import { TestUsers } from '../../../interfaces/scenarios.js';
describe('Users API Tests', () => {
let adminAccessToken: string;
let rootAdminAccessToken: string;
let testUsers: TestUsers;
beforeAll(async () => {
await startTestServer();
adminAccessToken = await loginAdminUser();
({ accessToken: rootAdminAccessToken } = await loginRootAdmin());
testUsers = await setupTestUsers();
});
afterAll(async () => {
await deleteAllUsers();
});
describe('Profile Tests', () => {
it('should return 200 and admin profile', async () => {
const response = await getMe(adminAccessToken);
it('should return root admin profile', async () => {
const response = await getMe(rootAdminAccessToken);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('userId', 'admin');
expect(response.body).toHaveProperty('userId', MEET_ENV.INITIAL_ADMIN_USER);
expect(response.body).toHaveProperty('name', 'Admin');
expect(response.body).toHaveProperty('role', 'admin');
expect(response.body).toHaveProperty('role', MeetUserRole.ADMIN);
expect(response.body).toHaveProperty('registrationDate');
expect(response.body).not.toHaveProperty('passwordHash');
expect(response.body).not.toHaveProperty('mustChangePassword');
});
it('should return ADMIN user profile', async () => {
const user = testUsers.admin;
const response = await getMe(user.accessToken);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('userId', user.user.userId);
expect(response.body).toHaveProperty('name', user.user.name);
expect(response.body).toHaveProperty('role', user.user.role);
expect(response.body).toHaveProperty('registrationDate', user.user.registrationDate);
expect(response.body).not.toHaveProperty('passwordHash');
expect(response.body).not.toHaveProperty('mustChangePassword');
});
it('should return USER user profile', async () => {
const user = testUsers.user;
const response = await getMe(user.accessToken);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('userId', user.user.userId);
expect(response.body).toHaveProperty('name', user.user.name);
expect(response.body).toHaveProperty('role', user.user.role);
expect(response.body).toHaveProperty('registrationDate', user.user.registrationDate);
expect(response.body).not.toHaveProperty('passwordHash');
expect(response.body).not.toHaveProperty('mustChangePassword');
});
it('should return ROOM_MEMBER user profile', async () => {
const user = testUsers.roomMember;
const response = await getMe(user.accessToken);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('userId', user.user.userId);
expect(response.body).toHaveProperty('name', user.user.name);
expect(response.body).toHaveProperty('role', user.user.role);
expect(response.body).toHaveProperty('registrationDate', user.user.registrationDate);
expect(response.body).not.toHaveProperty('passwordHash');
expect(response.body).not.toHaveProperty('mustChangePassword');
});
});
});