mini-auth.service.test.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
  2. import { DataSource } from 'typeorm';
  3. import { MiniAuthService } from '../../src/services';
  4. import { UserEntity } from '@d8d/user-module';
  5. // Mock 依赖
  6. vi.mock('@d8d/shared-utils', async (importOriginal) => {
  7. const actual = await importOriginal() as any;
  8. return {
  9. ...actual,
  10. JWTUtil: {
  11. generateToken: vi.fn().mockReturnValue('mock-jwt-token')
  12. },
  13. redisUtil: {
  14. setSessionKey: vi.fn().mockResolvedValue(undefined),
  15. getSessionKey: vi.fn().mockResolvedValue('mock-session-key')
  16. }
  17. };
  18. });
  19. vi.mock('@d8d/file-module', () => ({
  20. FileService: vi.fn().mockImplementation(() => ({
  21. downloadAndSaveFromUrl: vi.fn().mockResolvedValue({ file: { id: 1 } })
  22. }))
  23. }));
  24. describe('MiniAuthService', () => {
  25. let miniAuthService: MiniAuthService;
  26. let mockDataSource: DataSource;
  27. let mockUserRepository: any;
  28. beforeEach(() => {
  29. // Mock DataSource
  30. mockUserRepository = {
  31. findOne: vi.fn(),
  32. create: vi.fn(),
  33. save: vi.fn()
  34. };
  35. mockDataSource = {
  36. getRepository: vi.fn().mockReturnValue(mockUserRepository)
  37. } as any;
  38. miniAuthService = new MiniAuthService(mockDataSource);
  39. });
  40. afterEach(() => {
  41. vi.clearAllMocks();
  42. });
  43. describe('decryptPhoneNumber', () => {
  44. it('应该成功解密有效的手机号数据', async () => {
  45. // 模拟有效的加密数据、IV和sessionKey
  46. const encryptedData = 'valid_encrypted_data';
  47. const iv = 'valid_iv';
  48. const sessionKey = 'valid_session_key';
  49. // 这里我们模拟一个成功的解密过程
  50. // 在实际测试中,可能需要更复杂的模拟
  51. const result = await miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey);
  52. // 由于我们无法真正模拟 crypto 模块,这里主要测试方法调用
  53. expect(result).toBeDefined();
  54. });
  55. it('应该拒绝空的加密数据', async () => {
  56. const encryptedData = '';
  57. const iv = 'valid_iv';
  58. const sessionKey = 'valid_session_key';
  59. await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
  60. .rejects.toMatchObject({ code: 400, message: '加密数据或初始向量不能为空' });
  61. });
  62. it('应该拒绝空的初始向量', async () => {
  63. const encryptedData = 'valid_encrypted_data';
  64. const iv = '';
  65. const sessionKey = 'valid_session_key';
  66. await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
  67. .rejects.toMatchObject({ code: 400, message: '加密数据或初始向量不能为空' });
  68. });
  69. it('应该拒绝空的sessionKey', async () => {
  70. const encryptedData = 'valid_encrypted_data';
  71. const iv = 'valid_iv';
  72. const sessionKey = '';
  73. await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
  74. .rejects.toMatchObject({ code: 400, message: '加密数据或初始向量不能为空' });
  75. });
  76. it('应该处理解密失败的情况', async () => {
  77. // 模拟无效的加密数据
  78. const encryptedData = 'invalid_encrypted_data';
  79. const iv = 'invalid_iv';
  80. const sessionKey = 'invalid_session_key';
  81. // 由于我们无法真正模拟 crypto 模块,这里主要测试错误处理
  82. await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
  83. .rejects.toMatchObject({ code: 400 });
  84. });
  85. });
  86. describe('miniLogin', () => {
  87. it('应该成功处理小程序登录', async () => {
  88. // Mock 微信API响应
  89. const mockOpenidInfo = {
  90. openid: 'test_openid',
  91. session_key: 'test_session_key'
  92. };
  93. // Mock 用户数据
  94. const mockUser = {
  95. id: 1,
  96. username: 'wx_user',
  97. openid: 'test_openid'
  98. } as UserEntity;
  99. // Mock 方法
  100. vi.spyOn(miniAuthService as any, 'getOpenIdByCode').mockResolvedValue(mockOpenidInfo);
  101. mockUserRepository.findOne.mockResolvedValue(mockUser);
  102. const result = await miniAuthService.miniLogin('test_code');
  103. expect(result).toHaveProperty('token');
  104. expect(result).toHaveProperty('user');
  105. expect(result).toHaveProperty('isNewUser');
  106. expect(result.token).toBe('mock-jwt-token');
  107. expect(result.user).toEqual(mockUser);
  108. expect(result.isNewUser).toBe(false);
  109. });
  110. it('应该为新用户创建账户', async () => {
  111. // Mock 微信API响应
  112. const mockOpenidInfo = {
  113. openid: 'new_user_openid',
  114. session_key: 'test_session_key'
  115. };
  116. // Mock 新用户数据
  117. const mockNewUser = {
  118. id: 2,
  119. username: 'wx_new_user',
  120. openid: 'new_user_openid'
  121. } as UserEntity;
  122. // Mock 方法
  123. vi.spyOn(miniAuthService as any, 'getOpenIdByCode').mockResolvedValue(mockOpenidInfo);
  124. vi.spyOn(miniAuthService as any, 'createMiniUser').mockResolvedValue(mockNewUser);
  125. mockUserRepository.findOne.mockResolvedValue(null);
  126. const result = await miniAuthService.miniLogin('test_code');
  127. expect(result.isNewUser).toBe(true);
  128. expect(result.user).toEqual(mockNewUser);
  129. });
  130. });
  131. describe('updateUserProfile', () => {
  132. it('应该成功更新用户资料', async () => {
  133. const mockUser = {
  134. id: 1,
  135. nickname: 'old_nickname',
  136. avatarFileId: null
  137. } as UserEntity;
  138. mockUserRepository.findOne.mockResolvedValue(mockUser);
  139. mockUserRepository.save.mockResolvedValue({ ...mockUser, nickname: 'new_nickname' });
  140. const result = await miniAuthService.updateUserProfile(1, {
  141. nickname: 'new_nickname'
  142. });
  143. expect(result.nickname).toBe('new_nickname');
  144. expect(mockUserRepository.save).toHaveBeenCalled();
  145. });
  146. it('应该处理用户不存在的情况', async () => {
  147. mockUserRepository.findOne.mockResolvedValue(null);
  148. await expect(miniAuthService.updateUserProfile(999, { nickname: 'test' }))
  149. .rejects.toThrow('用户不存在');
  150. });
  151. });
  152. });