auth.service.test.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { describe, it, expect, vi, beforeEach } from 'vitest';
  2. import { AuthService, User, UserService } from '../../src/auth.service.js';
  3. import { EnableStatus } from '@d8d/shared-types';
  4. describe('认证服务', () => {
  5. let authService: AuthService;
  6. let mockUserService: UserService;
  7. const mockUser: User = {
  8. id: 1,
  9. username: 'testuser',
  10. nickname: '测试用户',
  11. isDisabled: EnableStatus.ENABLED,
  12. roles: [{ name: 'user' }]
  13. };
  14. beforeEach(() => {
  15. mockUserService = {
  16. getUserByUsername: vi.fn(),
  17. verifyPassword: vi.fn(),
  18. createUser: vi.fn()
  19. };
  20. authService = new AuthService(mockUserService);
  21. vi.stubEnv('JWT_SECRET', 'test-secret');
  22. });
  23. describe('登录', () => {
  24. it('应该成功登录', async () => {
  25. vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(mockUser);
  26. vi.mocked(mockUserService.verifyPassword).mockResolvedValue(true);
  27. const result = await authService.login('testuser', 'password');
  28. expect(result.token).toBeDefined();
  29. expect(result.user).toEqual(mockUser);
  30. expect(mockUserService.getUserByUsername).toHaveBeenCalledWith('testuser');
  31. expect(mockUserService.verifyPassword).toHaveBeenCalledWith(mockUser, 'password');
  32. });
  33. it('用户不存在时应该抛出错误', async () => {
  34. vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(null);
  35. await expect(authService.login('nonexistent', 'password'))
  36. .rejects
  37. .toThrow('用户不存在');
  38. });
  39. it('用户被禁用时应该抛出错误', async () => {
  40. const disabledUser = { ...mockUser, isDisabled: EnableStatus.DISABLED };
  41. vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(disabledUser);
  42. await expect(authService.login('testuser', 'password'))
  43. .rejects
  44. .toThrow('用户账户已被禁用');
  45. });
  46. it('密码错误时应该抛出错误', async () => {
  47. vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(mockUser);
  48. vi.mocked(mockUserService.verifyPassword).mockResolvedValue(false);
  49. await expect(authService.login('testuser', 'wrongpassword'))
  50. .rejects
  51. .toThrow('密码错误');
  52. });
  53. });
  54. describe('生成token', () => {
  55. it('应该成功生成token', () => {
  56. const token = authService.generateToken(mockUser);
  57. expect(token).toBeDefined();
  58. expect(typeof token).toBe('string');
  59. });
  60. it('应该使用自定义过期时间生成token', () => {
  61. const token = authService.generateToken(mockUser, '2h');
  62. expect(token).toBeDefined();
  63. });
  64. });
  65. describe('验证token', () => {
  66. it('应该成功验证token', () => {
  67. const token = authService.generateToken(mockUser);
  68. const payload = authService.verifyToken(token);
  69. expect(payload.id).toBe(mockUser.id);
  70. expect(payload.username).toBe(mockUser.username);
  71. });
  72. it('无效token应该抛出错误', () => {
  73. const invalidToken = 'invalid.token.here';
  74. expect(() => {
  75. authService.verifyToken(invalidToken);
  76. }).toThrow('无效的token');
  77. });
  78. });
  79. describe('权限验证', () => {
  80. it('应该验证用户有权限', () => {
  81. const hasPermission = authService.hasPermission(mockUser, 'user');
  82. expect(hasPermission).toBe(true);
  83. });
  84. it('应该验证用户没有权限', () => {
  85. const hasPermission = authService.hasPermission(mockUser, 'admin');
  86. expect(hasPermission).toBe(false);
  87. });
  88. it('应该验证用户有任意一个权限', () => {
  89. const hasAnyPermission = authService.hasAnyPermission(mockUser, ['user', 'admin']);
  90. expect(hasAnyPermission).toBe(true);
  91. });
  92. it('应该验证用户没有任意一个权限', () => {
  93. const hasAnyPermission = authService.hasAnyPermission(mockUser, ['admin', 'superuser']);
  94. expect(hasAnyPermission).toBe(false);
  95. });
  96. });
  97. describe('登出', () => {
  98. it('应该成功登出', async () => {
  99. const token = authService.generateToken(mockUser);
  100. await expect(authService.logout(token)).resolves.toBeUndefined();
  101. });
  102. it('无效token登出时应该抛出错误', async () => {
  103. const invalidToken = 'invalid.token.here';
  104. await expect(authService.logout(invalidToken))
  105. .rejects
  106. .toThrow('无效的token');
  107. });
  108. });
  109. });