supplier-management.integration.test.tsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import { describe, it, expect, vi, beforeEach } from 'vitest';
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react';
  3. import userEvent from '@testing-library/user-event';
  4. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  5. import { SupplierManagement } from '../../src/components/SupplierManagement';
  6. import { supplierClient } from '../../src/api/supplierClient';
  7. // 完整的mock响应对象
  8. const createMockResponse = (status: number, data?: any) => ({
  9. status,
  10. ok: status >= 200 && status < 300,
  11. body: null,
  12. bodyUsed: false,
  13. statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
  14. headers: new Headers(),
  15. url: '',
  16. redirected: false,
  17. type: 'basic' as ResponseType,
  18. json: async () => data || {},
  19. text: async () => '',
  20. blob: async () => new Blob(),
  21. arrayBuffer: async () => new ArrayBuffer(0),
  22. formData: async () => new FormData(),
  23. clone: function() { return this; }
  24. });
  25. // Mock API client
  26. vi.mock('../../src/api/supplierClient', () => {
  27. const mockSupplierClient = {
  28. index: {
  29. $get: vi.fn(() => Promise.resolve({ status: 200, body: null })),
  30. $post: vi.fn(() => Promise.resolve({ status: 201, body: null })),
  31. },
  32. ':id': {
  33. $put: vi.fn(() => Promise.resolve({ status: 200, body: null })),
  34. $delete: vi.fn(() => Promise.resolve({ status: 204, body: null })),
  35. },
  36. };
  37. const mockSupplierClientManager = {
  38. get: vi.fn(() => mockSupplierClient),
  39. };
  40. return {
  41. supplierClientManager: mockSupplierClientManager,
  42. supplierClient: mockSupplierClient,
  43. };
  44. });
  45. // Mock toast
  46. vi.mock('sonner', () => ({
  47. toast: {
  48. success: vi.fn(() => {}),
  49. error: vi.fn(() => {}),
  50. },
  51. }));
  52. const createTestQueryClient = () =>
  53. new QueryClient({
  54. defaultOptions: {
  55. queries: {
  56. retry: false,
  57. },
  58. },
  59. });
  60. const renderWithProviders = (component: React.ReactElement) => {
  61. const queryClient = createTestQueryClient();
  62. return render(
  63. <QueryClientProvider client={queryClient}>
  64. {component as any}
  65. </QueryClientProvider>
  66. );
  67. };
  68. describe('供应商管理集成测试', () => {
  69. beforeEach(() => {
  70. vi.clearAllMocks();
  71. });
  72. it('应该完成完整的供应商CRUD流程', async () => {
  73. const user = userEvent.setup();
  74. const mockSuppliers = {
  75. data: [
  76. {
  77. id: 1,
  78. name: '测试供应商',
  79. username: 'testsupplier',
  80. realname: '张经理',
  81. phone: '13800138000',
  82. state: 1,
  83. createdAt: '2024-01-01T00:00:00Z',
  84. },
  85. ],
  86. pagination: {
  87. total: 1,
  88. page: 1,
  89. pageSize: 10,
  90. },
  91. };
  92. const { toast } = await import('sonner');
  93. // Mock initial supplier list
  94. (supplierClient.index.$get as any).mockResolvedValue(createMockResponse(200, mockSuppliers));
  95. renderWithProviders(<SupplierManagement />);
  96. // Wait for initial data to load
  97. await waitFor(() => {
  98. expect(screen.getByText('测试供应商')).toBeInTheDocument();
  99. });
  100. // Test create supplier
  101. const createButton = screen.getByTestId('create-supplier-button');
  102. fireEvent.click(createButton);
  103. // Wait for dialog to open
  104. await waitFor(() => {
  105. expect(screen.getByTestId('create-supplier-submit-button')).toBeInTheDocument();
  106. });
  107. // Fill create form using placeholder text with fireEvent.change
  108. const nameInput = screen.getByPlaceholderText('请输入供应商名称');
  109. const usernameInput = screen.getByPlaceholderText('请输入用户名');
  110. const passwordInput = screen.getByPlaceholderText('请输入密码');
  111. const phoneInput = screen.getByPlaceholderText('请输入手机号码');
  112. fireEvent.change(nameInput, { target: { value: '新供应商' } });
  113. fireEvent.change(usernameInput, { target: { value: 'newsupplier' } });
  114. fireEvent.change(passwordInput, { target: { value: 'password123' } });
  115. fireEvent.change(phoneInput, { target: { value: '13800138000' } });
  116. // Mock successful creation
  117. (supplierClient.index.$post as any).mockResolvedValue(createMockResponse(201, { id: 2, name: '新供应商' }));
  118. const submitButton = screen.getByTestId('create-supplier-submit-button');
  119. await user.click(submitButton);
  120. await waitFor(() => {
  121. expect(supplierClient.index.$post).toHaveBeenCalledWith({
  122. json: {
  123. name: '新供应商',
  124. username: 'newsupplier',
  125. password: 'password123',
  126. phone: '13800138000',
  127. realname: '',
  128. state: 2,
  129. },
  130. });
  131. expect(toast.success).toHaveBeenCalledWith('创建成功');
  132. });
  133. // Test edit supplier
  134. const editButton = screen.getByTestId('edit-supplier-1');
  135. fireEvent.click(editButton);
  136. // Verify edit form is populated
  137. await waitFor(() => {
  138. expect(screen.getByDisplayValue('测试供应商')).toBeInTheDocument();
  139. });
  140. // Update supplier
  141. const updateNameInput = screen.getByDisplayValue('测试供应商');
  142. fireEvent.change(updateNameInput, { target: { value: '更新供应商' } });
  143. // Mock successful update
  144. (supplierClient[':id']['$put'] as any).mockResolvedValue(createMockResponse(200));
  145. const updateButton = screen.getByTestId('update-supplier-submit-button');
  146. await user.click(updateButton);
  147. await waitFor(() => {
  148. expect(supplierClient[':id']['$put']).toHaveBeenCalledWith({
  149. param: { id: 1 },
  150. json: {
  151. name: '更新供应商',
  152. username: 'testsupplier',
  153. phone: '13800138000',
  154. realname: '张经理',
  155. password: undefined,
  156. state: 1,
  157. },
  158. });
  159. expect(toast.success).toHaveBeenCalledWith('更新成功');
  160. });
  161. // Test delete supplier
  162. const deleteButton = screen.getByTestId('delete-supplier-1');
  163. fireEvent.click(deleteButton);
  164. // Confirm deletion
  165. expect(screen.getByText('确认删除')).toBeInTheDocument();
  166. // Mock successful deletion
  167. (supplierClient[':id']['$delete'] as any).mockResolvedValue({
  168. status: 204,
  169. });
  170. const confirmDeleteButton = screen.getByTestId('confirm-delete-button');
  171. await user.click(confirmDeleteButton);
  172. await waitFor(() => {
  173. expect(supplierClient[':id']['$delete']).toHaveBeenCalledWith({
  174. param: { id: 1 },
  175. });
  176. expect(toast.success).toHaveBeenCalledWith('删除成功');
  177. });
  178. });
  179. it('应该优雅处理API错误', async () => {
  180. const { supplierClient } = await import('../../src/api/supplierClient');
  181. const { toast } = await import('sonner');
  182. const user = userEvent.setup();
  183. // Mock API error
  184. (supplierClient.index.$get as any).mockRejectedValue(new Error('API Error'));
  185. renderWithProviders(<SupplierManagement />);
  186. // Should handle error without crashing
  187. await waitFor(() => {
  188. expect(screen.getByText('供应商管理')).toBeInTheDocument();
  189. });
  190. // Test create supplier error
  191. const createButton = screen.getByText('创建供应商');
  192. fireEvent.click(createButton);
  193. const nameInput = screen.getByPlaceholderText('请输入供应商名称');
  194. const usernameInput = screen.getByPlaceholderText('请输入用户名');
  195. const passwordInput = screen.getByPlaceholderText('请输入密码');
  196. const phoneInput = screen.getByPlaceholderText('请输入手机号码');
  197. fireEvent.change(nameInput, { target: { value: '测试供应商' } });
  198. fireEvent.change(usernameInput, { target: { value: 'testsupplier' } });
  199. fireEvent.change(passwordInput, { target: { value: 'password' } });
  200. fireEvent.change(phoneInput, { target: { value: '13800138000' } });
  201. // Mock creation error
  202. (supplierClient.index.$post as any).mockRejectedValue(new Error('Creation failed'));
  203. const submitButton = screen.getByTestId('create-supplier-submit-button');
  204. await user.click(submitButton);
  205. await waitFor(() => {
  206. expect(toast.error).toHaveBeenCalledWith('操作失败,请重试');
  207. });
  208. });
  209. it('应该处理搜索功能', async () => {
  210. const { supplierClient } = await import('../../src/api/supplierClient');
  211. const mockSuppliers = {
  212. data: [],
  213. pagination: { total: 0, page: 1, pageSize: 10 },
  214. };
  215. (supplierClient.index.$get as any).mockResolvedValue(createMockResponse(200, mockSuppliers));
  216. renderWithProviders(<SupplierManagement />);
  217. // Test search
  218. const searchInput = screen.getByTestId('search-input');
  219. fireEvent.change(searchInput, { target: { value: '搜索关键词' } });
  220. const searchButton = screen.getByTestId('search-button');
  221. fireEvent.click(searchButton);
  222. await waitFor(() => {
  223. expect(supplierClient.index.$get).toHaveBeenCalledWith({
  224. query: {
  225. page: 1,
  226. pageSize: 10,
  227. keyword: '搜索关键词',
  228. },
  229. });
  230. });
  231. });
  232. it('应该显示供应商状态', async () => {
  233. const mockSuppliers = {
  234. data: [
  235. {
  236. id: 1,
  237. name: '启用供应商',
  238. username: 'enabledsupplier',
  239. realname: '李经理',
  240. phone: '13900139000',
  241. state: 1,
  242. createdAt: '2024-01-01T00:00:00Z',
  243. },
  244. {
  245. id: 2,
  246. name: '禁用供应商',
  247. username: 'disabledsupplier',
  248. realname: '王经理',
  249. phone: '13700137000',
  250. state: 2,
  251. createdAt: '2024-01-02T00:00:00Z',
  252. },
  253. ],
  254. pagination: {
  255. total: 2,
  256. page: 1,
  257. pageSize: 10,
  258. },
  259. };
  260. (supplierClient.index.$get as any).mockResolvedValue(createMockResponse(200, mockSuppliers));
  261. renderWithProviders(<SupplierManagement />);
  262. await waitFor(() => {
  263. expect(screen.getByText('启用')).toBeInTheDocument();
  264. expect(screen.getByText('禁用')).toBeInTheDocument();
  265. });
  266. });
  267. });