2
0

users.integration.test.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
  2. import { OpenAPIHono } from '@hono/zod-openapi';
  3. import { createApiClient, ApiClient } from '../../__test_utils__/api-client';
  4. import { createMockDataSource } from '../../__test_utils__/test-db';
  5. // Mock 数据源
  6. vi.mock('../../../data-source', () => {
  7. const mockDataSource = createMockDataSource();
  8. return {
  9. AppDataSource: mockDataSource
  10. };
  11. });
  12. // Mock 用户服务
  13. vi.mock('../../modules/users/user.service', () => ({
  14. UserService: vi.fn().mockImplementation(() => ({
  15. getUsersWithPagination: vi.fn().mockResolvedValue([[], 0]),
  16. getUserById: vi.fn().mockResolvedValue(null),
  17. createUser: vi.fn().mockResolvedValue({ id: 1, username: 'testuser' }),
  18. updateUser: vi.fn().mockResolvedValue({ affected: 1 }),
  19. deleteUser: vi.fn().mockResolvedValue({ affected: 1 })
  20. }))
  21. }));
  22. // Mock 认证中间件
  23. vi.mock('../../middleware/auth.middleware', () => ({
  24. authMiddleware: vi.fn().mockImplementation((_c, next) => next())
  25. }));
  26. // Mock 通用CRUD服务
  27. vi.mock('../../utils/generic-crud.service', () => ({
  28. GenericCrudService: vi.fn().mockImplementation(() => ({
  29. getList: vi.fn().mockResolvedValue([[], 0]),
  30. getById: vi.fn().mockResolvedValue(null),
  31. create: vi.fn().mockResolvedValue({ id: 1, username: 'testuser' }),
  32. update: vi.fn().mockResolvedValue({ affected: 1 }),
  33. delete: vi.fn().mockResolvedValue({ affected: 1 })
  34. }))
  35. }));
  36. describe('Users API Integration Tests', () => {
  37. let app: OpenAPIHono;
  38. let apiClient: ApiClient;
  39. let mockDataSource: any;
  40. beforeEach(async () => {
  41. vi.clearAllMocks();
  42. // 动态导入用户路由
  43. const userRoutes = await import('../users/index');
  44. // 使用导入的应用实例
  45. app = userRoutes.default;
  46. // 创建API客户端
  47. apiClient = createApiClient(app, {
  48. authToken: 'test-token-123'
  49. });
  50. });
  51. afterEach(() => {
  52. vi.resetAllMocks();
  53. });
  54. describe('GET /users', () => {
  55. it('应该返回用户列表和分页信息', async () => {
  56. // 模拟通用CRUD服务返回数据
  57. const mockCrudService = require('../../utils/generic-crud.service').GenericCrudService();
  58. const mockUsers = [
  59. { id: 1, username: 'user1', email: 'user1@example.com' },
  60. { id: 2, username: 'user2', email: 'user2@example.com' }
  61. ];
  62. mockCrudService.getList.mockResolvedValue([mockUsers, 2]);
  63. const response = await apiClient.get('/users?page=1&pageSize=10');
  64. expect(response.status).toBe(200);
  65. expect(response.data).toEqual({
  66. data: mockUsers,
  67. pagination: {
  68. total: 2,
  69. current: 1,
  70. pageSize: 10
  71. }
  72. });
  73. });
  74. it('应该验证分页参数', async () => {
  75. const response = await apiClient.get('/users?page=0&pageSize=0');
  76. expect(response.status).toBe(400);
  77. expect(response.data).toMatchObject({
  78. success: false,
  79. error: expect.any(Object)
  80. });
  81. });
  82. it('应该支持关键词搜索', async () => {
  83. const mockCrudService = require('../../utils/generic-crud.service').GenericCrudService();
  84. mockCrudService.getList.mockResolvedValue([[], 0]);
  85. const response = await apiClient.get('/users?page=1&pageSize=10&keyword=admin');
  86. expect(response.status).toBe(200);
  87. expect(mockCrudService.getList).toHaveBeenCalledWith(
  88. expect.objectContaining({
  89. page: 1,
  90. pageSize: 10,
  91. keyword: 'admin'
  92. })
  93. );
  94. });
  95. });
  96. describe('GET /users/:id', () => {
  97. it('应该返回特定用户信息', async () => {
  98. const mockUser = { id: 1, username: 'testuser', email: 'test@example.com' };
  99. const mockCrudService = require('../../utils/generic-crud.service').GenericCrudService();
  100. mockCrudService.getById.mockResolvedValue(mockUser);
  101. const response = await apiClient.get('/users/1');
  102. expect(response.status).toBe(200);
  103. expect(response.data).toEqual(mockUser);
  104. expect(mockCrudService.getById).toHaveBeenCalledWith(1);
  105. });
  106. it('应该在用户不存在时返回404', async () => {
  107. const mockCrudService = require('../../utils/generic-crud.service').GenericCrudService();
  108. mockCrudService.getById.mockResolvedValue(null);
  109. const response = await apiClient.get('/users/999');
  110. expect(response.status).toBe(404);
  111. expect(response.data).toMatchObject({
  112. code: 404,
  113. message: expect.any(String)
  114. });
  115. });
  116. it('应该验证用户ID格式', async () => {
  117. const response = await apiClient.get('/users/invalid');
  118. expect(response.status).toBe(400);
  119. expect(response.data).toMatchObject({
  120. success: false,
  121. error: expect.any(Object)
  122. });
  123. });
  124. });
  125. describe('错误处理', () => {
  126. it('应该在服务错误时返回500状态码', async () => {
  127. const mockCrudService = require('../../utils/generic-crud.service').GenericCrudService();
  128. mockCrudService.getList.mockRejectedValue(new Error('Database error'));
  129. const response = await apiClient.get('/users?page=1&pageSize=10');
  130. expect(response.status).toBe(500);
  131. expect(response.data).toMatchObject({
  132. code: 500,
  133. message: 'Database error'
  134. });
  135. });
  136. it('应该在未知错误时返回通用错误消息', async () => {
  137. const mockCrudService = require('../../utils/generic-crud.service').GenericCrudService();
  138. mockCrudService.getList.mockRejectedValue('Unknown error');
  139. const response = await apiClient.get('/users?page=1&pageSize=10');
  140. expect(response.status).toBe(500);
  141. expect(response.data).toMatchObject({
  142. code: 500,
  143. message: '获取用户列表失败'
  144. });
  145. });
  146. });
  147. describe('认证和授权', () => {
  148. it('应该在缺少认证令牌时返回401', async () => {
  149. apiClient.clearAuthToken();
  150. const response = await apiClient.get('/users');
  151. expect(response.status).toBe(401);
  152. expect(response.data).toMatchObject({
  153. code: 401,
  154. message: expect.any(String)
  155. });
  156. });
  157. it('应该在无效令牌时返回401', async () => {
  158. // 模拟认证中间件验证失败
  159. const authMiddleware = require('../../middleware/auth.middleware').authMiddleware;
  160. authMiddleware.mockImplementation((c, next) => {
  161. return c.json({ error: 'Invalid token' }, 401);
  162. });
  163. const response = await apiClient.get('/users');
  164. expect(response.status).toBe(401);
  165. expect(response.data).toEqual({ error: 'Invalid token' });
  166. });
  167. });
  168. });