import { UserEntity } from '@app/database/entities/user.entity'; import { BadRequestException, NotFoundException } from '@nestjs/common'; import { AuthUserDto } from '../../decorators/auth-user.decorator'; import { IUserRepository } from './user-repository'; import { UserService } from './user.service'; describe('UserService', () => { let sui: UserService; let userRepositoryMock: jest.Mocked; const adminAuthUser: AuthUserDto = Object.freeze({ id: 'admin_id', email: 'admin@test.com', }); const immichAuthUser: AuthUserDto = Object.freeze({ id: 'immich_id', email: 'immich@test.com', }); const adminUser: UserEntity = Object.freeze({ id: 'admin_id', email: 'admin@test.com', password: 'admin_password', salt: 'admin_salt', firstName: 'admin_first_name', lastName: 'admin_last_name', isAdmin: true, shouldChangePassword: false, profileImagePath: '', createdAt: '2021-01-01', }); const immichUser: UserEntity = Object.freeze({ id: 'immich_id', email: 'immich@test.com', password: 'immich_password', salt: 'immich_salt', firstName: 'immich_first_name', lastName: 'immich_last_name', isAdmin: false, shouldChangePassword: false, profileImagePath: '', createdAt: '2021-01-01', }); const updatedImmichUser: UserEntity = Object.freeze({ id: 'immich_id', email: 'immich@test.com', password: 'immich_password', salt: 'immich_salt', firstName: 'updated_immich_first_name', lastName: 'updated_immich_last_name', isAdmin: false, shouldChangePassword: true, profileImagePath: '', createdAt: '2021-01-01', }); beforeAll(() => { userRepositoryMock = { create: jest.fn(), createProfileImage: jest.fn(), get: jest.fn(), getByEmail: jest.fn(), getList: jest.fn(), update: jest.fn(), }; sui = new UserService(userRepositoryMock); }); it('should be defined', () => { expect(sui).toBeDefined(); }); describe('Update user', () => { it('should update user', () => { const requestor = immichAuthUser; const userToUpdate = immichUser; userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(immichUser)); userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(userToUpdate)); userRepositoryMock.update.mockImplementationOnce(() => Promise.resolve(updatedImmichUser)); const result = sui.updateUser(requestor, { id: userToUpdate.id, shouldChangePassword: true, }); expect(result).resolves.toBeDefined(); }); it('user can only update its information', () => { const requestor = immichAuthUser; userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(immichUser)); const result = sui.updateUser(requestor, { id: 'not_immich_auth_user_id', password: 'I take over your account now', }); expect(result).rejects.toBeInstanceOf(BadRequestException); }); it('admin can update any user information', async () => { const requestor = adminAuthUser; const userToUpdate = immichUser; userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(adminUser)); userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(userToUpdate)); userRepositoryMock.update.mockImplementationOnce(() => Promise.resolve(updatedImmichUser)); const result = await sui.updateUser(requestor, { id: userToUpdate.id, shouldChangePassword: true, }); expect(result).toBeDefined(); expect(result.id).toEqual(updatedImmichUser.id); expect(result.shouldChangePassword).toEqual(updatedImmichUser.shouldChangePassword); }); it('update user information should throw error if user not found', () => { const requestor = adminAuthUser; const userToUpdate = immichUser; userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(adminUser)); userRepositoryMock.get.mockImplementationOnce(() => Promise.resolve(null)); const result = sui.updateUser(requestor, { id: userToUpdate.id, shouldChangePassword: true, }); expect(result).rejects.toBeInstanceOf(NotFoundException); }); }); });