user-selector.integration.test.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import { describe, it, expect, vi, beforeEach } from 'vitest';
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react';
  3. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  4. import { UserSelector } from '../../src/components/UserSelector';
  5. import { userClient } from '../../src/api/userClient';
  6. // 完整的mock响应对象
  7. const createMockResponse = (status: number, data?: any) => ({
  8. status,
  9. ok: status >= 200 && status < 300,
  10. body: null,
  11. bodyUsed: false,
  12. statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
  13. headers: new Headers(),
  14. url: '',
  15. redirected: false,
  16. type: 'basic' as ResponseType,
  17. json: async () => data || {},
  18. text: async () => '',
  19. blob: async () => new Blob(),
  20. arrayBuffer: async () => new ArrayBuffer(0),
  21. formData: async () => new FormData(),
  22. clone: function() { return this; }
  23. });
  24. // Mock API client
  25. vi.mock('../../src/api/userClient', () => {
  26. const mockUserClient = {
  27. $get: vi.fn(() => Promise.resolve({
  28. status: 200,
  29. body: null,
  30. json: async () => ({ data: [], pagination: { total: 0, page: 1, pageSize: 100 } })
  31. })),
  32. };
  33. const mockUserClientManager = {
  34. get: vi.fn(() => mockUserClient),
  35. };
  36. return {
  37. userClientManager: mockUserClientManager,
  38. userClient: mockUserClient,
  39. };
  40. });
  41. const createTestQueryClient = () =>
  42. new QueryClient({
  43. defaultOptions: {
  44. queries: {
  45. retry: false,
  46. enabled: true,
  47. },
  48. },
  49. });
  50. const renderWithProviders = (component: React.ReactElement) => {
  51. const queryClient = createTestQueryClient();
  52. return render(
  53. <QueryClientProvider client={queryClient}>
  54. {component as any}
  55. </QueryClientProvider>
  56. );
  57. };
  58. describe('用户选择器集成测试', () => {
  59. beforeEach(() => {
  60. vi.clearAllMocks();
  61. });
  62. it('应该加载并显示用户列表', async () => {
  63. const mockUsers = {
  64. data: [
  65. {
  66. id: 1,
  67. username: 'user1',
  68. name: 'User One',
  69. email: 'user1@example.com',
  70. phone: '1234567890',
  71. },
  72. {
  73. id: 2,
  74. username: 'user2',
  75. name: 'User Two',
  76. email: 'user2@example.com',
  77. phone: '0987654321',
  78. },
  79. ],
  80. pagination: {
  81. total: 2,
  82. page: 1,
  83. pageSize: 100,
  84. },
  85. };
  86. // Mock user list API
  87. (userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
  88. renderWithProviders(<UserSelector testId="user-selector" />);
  89. // Open select dropdown to trigger API call
  90. const selectTrigger = screen.getByTestId('user-selector');
  91. fireEvent.click(selectTrigger);
  92. // Wait for API call and loading to complete
  93. await waitFor(() => {
  94. expect(userClient.$get).toHaveBeenCalledWith({
  95. query: {
  96. page: 1,
  97. pageSize: 100,
  98. },
  99. });
  100. });
  101. // Verify select trigger is rendered
  102. expect(selectTrigger).toBeInTheDocument();
  103. });
  104. it('应该处理用户选择', async () => {
  105. const mockUsers = {
  106. data: [
  107. {
  108. id: 1,
  109. username: 'user1',
  110. name: 'User One',
  111. email: 'user1@example.com',
  112. phone: '1234567890',
  113. },
  114. ],
  115. pagination: {
  116. total: 1,
  117. page: 1,
  118. pageSize: 100,
  119. },
  120. };
  121. const mockOnChange = vi.fn();
  122. // Mock user list API
  123. (userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
  124. renderWithProviders(
  125. <UserSelector onChange={mockOnChange} testId="user-selector" />
  126. );
  127. // Wait for API call
  128. await waitFor(() => {
  129. expect(userClient.$get).toHaveBeenCalledWith({
  130. query: {
  131. page: 1,
  132. pageSize: 100,
  133. },
  134. });
  135. });
  136. // Verify select trigger is rendered
  137. const selectTrigger = screen.getByTestId('user-selector');
  138. expect(selectTrigger).toBeInTheDocument();
  139. // Verify onChange callback is properly passed
  140. expect(mockOnChange).not.toHaveBeenCalled();
  141. });
  142. it('应该显示自定义占位符', async () => {
  143. const mockUsers = {
  144. data: [],
  145. pagination: {
  146. total: 0,
  147. page: 1,
  148. pageSize: 100,
  149. },
  150. };
  151. // Mock empty user list
  152. (userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
  153. renderWithProviders(
  154. <UserSelector placeholder="请选择用户" testId="user-selector" />
  155. );
  156. // Open select dropdown to trigger API call
  157. const selectTrigger = screen.getByTestId('user-selector');
  158. fireEvent.click(selectTrigger);
  159. // Wait for API call
  160. await waitFor(() => {
  161. expect(userClient.$get).toHaveBeenCalled();
  162. });
  163. // Verify custom placeholder is shown
  164. expect(selectTrigger).toHaveTextContent('请选择用户');
  165. });
  166. it('应该处理禁用状态', async () => {
  167. const mockUsers = {
  168. data: [
  169. {
  170. id: 1,
  171. username: 'user1',
  172. name: 'User One',
  173. email: 'user1@example.com',
  174. phone: '1234567890',
  175. },
  176. ],
  177. pagination: {
  178. total: 1,
  179. page: 1,
  180. pageSize: 100,
  181. },
  182. };
  183. // Mock user list API
  184. (userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
  185. renderWithProviders(
  186. <UserSelector disabled={true} testId="user-selector" />
  187. );
  188. // Verify select is disabled immediately (no need to wait for API call)
  189. const selectTrigger = screen.getByTestId('user-selector');
  190. expect(selectTrigger).toBeDisabled();
  191. });
  192. it('应该处理API错误', async () => {
  193. // Mock API error
  194. (userClient.$get as any).mockRejectedValue(new Error('API Error'));
  195. renderWithProviders(<UserSelector testId="user-selector" />);
  196. // Should handle error without crashing
  197. await waitFor(() => {
  198. expect(screen.getByTestId('user-selector')).toBeInTheDocument();
  199. });
  200. });
  201. it('应该显示预选值', async () => {
  202. const mockUsers = {
  203. data: [
  204. {
  205. id: 1,
  206. username: 'user1',
  207. name: 'User One',
  208. email: 'user1@example.com',
  209. phone: '1234567890',
  210. },
  211. {
  212. id: 2,
  213. username: 'user2',
  214. name: 'User Two',
  215. email: 'user2@example.com',
  216. phone: '0987654321',
  217. },
  218. ],
  219. pagination: {
  220. total: 2,
  221. page: 1,
  222. pageSize: 100,
  223. },
  224. };
  225. // Mock user list API
  226. (userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
  227. renderWithProviders(
  228. <UserSelector value={2} testId="user-selector" />
  229. );
  230. // Wait for data to load
  231. await waitFor(() => {
  232. expect(userClient.$get).toHaveBeenCalled();
  233. });
  234. // Verify the select has the correct value
  235. const selectTrigger = screen.getByTestId('user-selector');
  236. expect(selectTrigger).toHaveAttribute('data-state', 'closed');
  237. });
  238. });