user.service.test.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import { describe, it, expect, beforeEach, vi } from 'vitest';
  2. import { UserService } from '../../src/services/user.service';
  3. import { UserEntity } from '../../src/entities/user.entity';
  4. import { Role } from '../../src/entities/role.entity';
  5. import { DataSource, Repository } from 'typeorm';
  6. // Mock DataSource
  7. const mockDataSource = {
  8. getRepository: vi.fn()
  9. } as unknown as DataSource;
  10. // Mock repositories
  11. const mockUserRepository = {
  12. create: vi.fn(),
  13. save: vi.fn(),
  14. findOne: vi.fn(),
  15. update: vi.fn(),
  16. delete: vi.fn(),
  17. find: vi.fn(),
  18. findByIds: vi.fn()
  19. } as unknown as Repository<UserEntity>;
  20. const mockRoleRepository = {
  21. findByIds: vi.fn()
  22. } as unknown as Repository<Role>;
  23. describe('UserService', () => {
  24. let userService: UserService;
  25. beforeEach(() => {
  26. vi.clearAllMocks();
  27. // Setup mock repositories
  28. vi.mocked(mockDataSource.getRepository)
  29. .mockReturnValueOnce(mockUserRepository)
  30. .mockReturnValueOnce(mockRoleRepository);
  31. userService = new UserService(mockDataSource);
  32. });
  33. describe('createUser', () => {
  34. it('should create a user with hashed password', async () => {
  35. const userData = {
  36. username: 'testuser',
  37. password: 'password123',
  38. email: 'test@example.com'
  39. };
  40. const mockUser = {
  41. id: 1,
  42. ...userData,
  43. password: 'hashed_password',
  44. phone: null,
  45. nickname: null,
  46. name: null,
  47. avatarFileId: null,
  48. disabledStatus: 'enabled',
  49. deleteStatus: 'active',
  50. createdAt: new Date(),
  51. updatedAt: new Date(),
  52. roles: []
  53. } as unknown as UserEntity;
  54. vi.mocked(mockUserRepository.create).mockReturnValue(mockUser);
  55. vi.mocked(mockUserRepository.save).mockResolvedValue(mockUser);
  56. const result = await userService.createUser(userData);
  57. expect(mockUserRepository.create).toHaveBeenCalledWith({
  58. ...userData,
  59. password: expect.not.stringMatching('password123') // Password should be hashed
  60. });
  61. expect(mockUserRepository.save).toHaveBeenCalledWith(mockUser);
  62. expect(result).toEqual(mockUser);
  63. });
  64. it('should throw error when creation fails', async () => {
  65. const userData = {
  66. username: 'testuser',
  67. password: 'password123'
  68. };
  69. vi.mocked(mockUserRepository.create).mockImplementation(() => {
  70. throw new Error('Database error');
  71. });
  72. await expect(userService.createUser(userData)).rejects.toThrow('Failed to create user');
  73. });
  74. });
  75. describe('getUserById', () => {
  76. it('should return user by id', async () => {
  77. const mockUser = {
  78. id: 1,
  79. username: 'testuser',
  80. password: 'hashedpassword',
  81. phone: null,
  82. email: 'test@example.com',
  83. nickname: null,
  84. name: null,
  85. avatarFileId: null,
  86. disabledStatus: 'enabled',
  87. deleteStatus: 'active',
  88. createdAt: new Date(),
  89. updatedAt: new Date(),
  90. roles: []
  91. } as unknown as UserEntity;
  92. vi.mocked(mockUserRepository.findOne).mockResolvedValue(mockUser);
  93. const result = await userService.getUserById(1);
  94. expect(mockUserRepository.findOne).toHaveBeenCalledWith({
  95. where: { id: 1 },
  96. relations: ['roles']
  97. });
  98. expect(result).toEqual(mockUser);
  99. });
  100. it('should return null when user not found', async () => {
  101. vi.mocked(mockUserRepository.findOne).mockResolvedValue(null);
  102. const result = await userService.getUserById(999);
  103. expect(result).toBeNull();
  104. });
  105. });
  106. describe('getUserByUsername', () => {
  107. it('should return user by username', async () => {
  108. const mockUser = {
  109. id: 1,
  110. username: 'testuser',
  111. password: 'hashedpassword',
  112. phone: null,
  113. email: 'test@example.com',
  114. nickname: null,
  115. name: null,
  116. avatarFileId: null,
  117. disabledStatus: 'enabled',
  118. deleteStatus: 'active',
  119. createdAt: new Date(),
  120. updatedAt: new Date(),
  121. roles: []
  122. } as unknown as UserEntity;
  123. vi.mocked(mockUserRepository.findOne).mockResolvedValue(mockUser);
  124. const result = await userService.getUserByUsername('testuser');
  125. expect(mockUserRepository.findOne).toHaveBeenCalledWith({
  126. where: { username: 'testuser' },
  127. relations: ['roles']
  128. });
  129. expect(result).toEqual(mockUser);
  130. });
  131. });
  132. describe('updateUser', () => {
  133. it('should update user with hashed password', async () => {
  134. const updateData = {
  135. password: 'newpassword',
  136. email: 'new@example.com'
  137. };
  138. const updatedUser = {
  139. id: 1,
  140. username: 'testuser',
  141. password: 'hashed_newpassword',
  142. email: 'new@example.com',
  143. roles: []
  144. } as unknown as UserEntity;
  145. vi.mocked(mockUserRepository.update).mockResolvedValue({ affected: 1 } as any);
  146. vi.mocked(mockUserRepository.findOne).mockResolvedValue(updatedUser);
  147. const result = await userService.updateUser(1, updateData);
  148. expect(mockUserRepository.update).toHaveBeenCalledWith(1, {
  149. ...updateData,
  150. password: expect.not.stringMatching('newpassword') // Password should be hashed
  151. });
  152. expect(result).toEqual(updatedUser);
  153. });
  154. });
  155. describe('deleteUser', () => {
  156. it('should delete user successfully', async () => {
  157. vi.mocked(mockUserRepository.delete).mockResolvedValue({ affected: 1 } as any);
  158. const result = await userService.deleteUser(1);
  159. expect(mockUserRepository.delete).toHaveBeenCalledWith(1);
  160. expect(result).toBe(true);
  161. });
  162. it('should return false when user not found', async () => {
  163. vi.mocked(mockUserRepository.delete).mockResolvedValue({ affected: 0 } as any);
  164. const result = await userService.deleteUser(999);
  165. expect(result).toBe(false);
  166. });
  167. });
  168. describe('assignRoles', () => {
  169. it('should assign roles to user', async () => {
  170. const mockUser = {
  171. id: 1,
  172. username: 'testuser',
  173. password: 'hashedpassword',
  174. phone: null,
  175. email: 'test@example.com',
  176. nickname: null,
  177. name: null,
  178. avatarFileId: null,
  179. disabledStatus: 'enabled',
  180. deleteStatus: 'active',
  181. createdAt: new Date(),
  182. updatedAt: new Date(),
  183. roles: []
  184. } as unknown as UserEntity;
  185. const mockRoles = [
  186. { id: 1, name: 'admin' } as Role,
  187. { id: 2, name: 'user' } as Role
  188. ];
  189. vi.mocked(mockUserRepository.findOne).mockResolvedValue(mockUser);
  190. vi.mocked(mockRoleRepository.findByIds).mockResolvedValue(mockRoles);
  191. vi.mocked(mockUserRepository.save).mockResolvedValue({
  192. ...mockUser,
  193. roles: mockRoles
  194. } as UserEntity);
  195. const result = await userService.assignRoles(1, [1, 2]);
  196. expect(mockRoleRepository.findByIds).toHaveBeenCalledWith([1, 2]);
  197. expect(mockUserRepository.save).toHaveBeenCalledWith({
  198. ...mockUser,
  199. roles: mockRoles
  200. });
  201. expect(result?.roles).toEqual(mockRoles);
  202. });
  203. it('should return null when user not found', async () => {
  204. vi.mocked(mockUserRepository.findOne).mockResolvedValue(null);
  205. const result = await userService.assignRoles(999, [1, 2]);
  206. expect(result).toBeNull();
  207. });
  208. });
  209. describe('getUsers', () => {
  210. it('should return all users', async () => {
  211. const mockUsers = [
  212. { id: 1, username: 'user1', roles: [] },
  213. { id: 2, username: 'user2', roles: [] }
  214. ] as unknown as UserEntity[];
  215. vi.mocked(mockUserRepository.find).mockResolvedValue(mockUsers);
  216. const result = await userService.getUsers();
  217. expect(mockUserRepository.find).toHaveBeenCalledWith({
  218. relations: ['roles']
  219. });
  220. expect(result).toEqual(mockUsers);
  221. });
  222. });
  223. describe('getUserByAccount', () => {
  224. it('should return user by username or email', async () => {
  225. const mockUser = {
  226. id: 1,
  227. username: 'testuser',
  228. email: 'test@example.com',
  229. roles: []
  230. } as unknown as UserEntity;
  231. vi.mocked(mockUserRepository.findOne).mockResolvedValue(mockUser);
  232. const result = await userService.getUserByAccount('testuser');
  233. expect(mockUserRepository.findOne).toHaveBeenCalledWith({
  234. where: [{ username: 'testuser' }, { email: 'testuser' }],
  235. relations: ['roles']
  236. });
  237. expect(result).toEqual(mockUser);
  238. });
  239. });
  240. });