user-selector.integration.test.tsx 6.9 KB

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