useAreas.test.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import React from 'react';
  2. import { describe, it, expect, vi, beforeEach } from 'vitest';
  3. import { renderHook, waitFor } from '@testing-library/react';
  4. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  5. import { useAreas, useCreateArea, useUpdateArea, useDeleteArea, useToggleAreaStatus } from '../../src/hooks/useAreas';
  6. import { areaClient } from '../../src/api/areaClient';
  7. // 完整的mock响应对象 - 按照用户UI包规范
  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 areaClient - 按照用户UI包规范
  26. vi.mock('../../src/api/areaClient', () => {
  27. const mockAreaClient = {
  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 mockAreaClientManager = {
  38. get: vi.fn(() => mockAreaClient),
  39. };
  40. return {
  41. areaClientManager: mockAreaClientManager,
  42. areaClient: mockAreaClient,
  43. };
  44. });
  45. // Mock sonner toast
  46. vi.mock('sonner', () => ({
  47. toast: {
  48. success: vi.fn(),
  49. error: vi.fn()
  50. }
  51. }));
  52. // Test wrapper component
  53. const createWrapper = () => {
  54. const queryClient = new QueryClient({
  55. defaultOptions: {
  56. queries: {
  57. retry: false,
  58. },
  59. },
  60. });
  61. return ({ children }: { children: React.ReactNode }) => (
  62. <QueryClientProvider client={queryClient}>
  63. {children}
  64. </QueryClientProvider>
  65. );
  66. };
  67. describe('useAreas Hook', () => {
  68. beforeEach(() => {
  69. vi.clearAllMocks();
  70. });
  71. it('should fetch areas successfully', async () => {
  72. const mockAreas = [
  73. {
  74. id: 1,
  75. name: '北京市',
  76. code: '110000',
  77. level: 1,
  78. parentId: null,
  79. isDisabled: 0
  80. }
  81. ];
  82. (areaClient.index.$get as any).mockResolvedValueOnce(createMockResponse(200, { data: mockAreas }));
  83. const { result } = renderHook(() => useAreas(), {
  84. wrapper: createWrapper()
  85. });
  86. // Initial loading state
  87. expect(result.current.isLoading).toBe(true);
  88. // Wait for data to load
  89. await waitFor(() => {
  90. expect(result.current.isSuccess).toBe(true);
  91. });
  92. expect(result.current.data).toEqual(mockAreas);
  93. expect(areaClient.index.$get).toHaveBeenCalledWith({
  94. query: {
  95. page: 1,
  96. pageSize: 100,
  97. filters: '',
  98. sortBy: 'id',
  99. sortOrder: 'ASC'
  100. }
  101. });
  102. });
  103. it('should handle fetch areas error', async () => {
  104. (areaClient.index.$get as any).mockRejectedValueOnce(new Error('API Error'));
  105. const { result } = renderHook(() => useAreas(), {
  106. wrapper: createWrapper()
  107. });
  108. // Wait for error
  109. await waitFor(() => {
  110. expect(result.current.isError).toBe(true);
  111. });
  112. expect(result.current.error).toBeDefined();
  113. });
  114. it('should create area successfully', async () => {
  115. const mockAreaData = {
  116. name: '北京市',
  117. code: '110000',
  118. level: 1,
  119. parentId: null,
  120. isDisabled: 0
  121. };
  122. (areaClient.index.$post as any).mockResolvedValueOnce(createMockResponse(201));
  123. const { result } = renderHook(() => useCreateArea(), {
  124. wrapper: createWrapper()
  125. });
  126. await result.current.mutateAsync(mockAreaData);
  127. expect(areaClient.index.$post).toHaveBeenCalledWith({
  128. json: mockAreaData
  129. });
  130. });
  131. it('should update area successfully', async () => {
  132. const mockUpdateData = {
  133. name: '北京市更新',
  134. code: '110000',
  135. level: 1,
  136. parentId: null,
  137. isDisabled: 0
  138. };
  139. (areaClient[':id'].$put as any).mockResolvedValueOnce(createMockResponse(200));
  140. const { result } = renderHook(() => useUpdateArea(), {
  141. wrapper: createWrapper()
  142. });
  143. await result.current.mutateAsync({
  144. id: 1,
  145. data: mockUpdateData
  146. });
  147. expect(areaClient[':id'].$put).toHaveBeenCalledWith({
  148. param: { id: 1 },
  149. json: mockUpdateData
  150. });
  151. });
  152. it('should delete area successfully', async () => {
  153. (areaClient[':id'].$delete as any).mockResolvedValueOnce(createMockResponse(204));
  154. const { result } = renderHook(() => useDeleteArea(), {
  155. wrapper: createWrapper()
  156. });
  157. await result.current.mutateAsync(1);
  158. expect(areaClient[':id'].$delete).toHaveBeenCalledWith({
  159. param: { id: 1 }
  160. });
  161. });
  162. it('should toggle area status successfully', async () => {
  163. (areaClient[':id'].$put as any).mockResolvedValueOnce(createMockResponse(200));
  164. const { result } = renderHook(() => useToggleAreaStatus(), {
  165. wrapper: createWrapper()
  166. });
  167. await result.current.mutateAsync({
  168. id: 1,
  169. isDisabled: 1
  170. });
  171. expect(areaClient[':id'].$put).toHaveBeenCalledWith({
  172. param: { id: 1 },
  173. json: { isDisabled: 1 }
  174. });
  175. });
  176. });