useAreas.test.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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('应该成功获取区域数据', async () => {
  72. const mockAreas = [
  73. {
  74. id: 1,
  75. tenantId: 1,
  76. name: '北京市',
  77. code: '110000',
  78. level: 1,
  79. parentId: null,
  80. isDisabled: 0
  81. }
  82. ];
  83. (areaClient.index.$get as any).mockResolvedValueOnce(createMockResponse(200, { data: mockAreas }));
  84. const { result } = renderHook(() => useAreas(), {
  85. wrapper: createWrapper()
  86. });
  87. // Initial loading state
  88. expect(result.current.isLoading).toBe(true);
  89. // Wait for data to load
  90. await waitFor(() => {
  91. expect(result.current.isSuccess).toBe(true);
  92. });
  93. expect(result.current.data).toEqual(mockAreas);
  94. expect(areaClient.index.$get).toHaveBeenCalledWith({
  95. query: {
  96. page: 1,
  97. pageSize: 100,
  98. filters: '',
  99. sortBy: 'id',
  100. sortOrder: 'ASC'
  101. }
  102. });
  103. });
  104. it('应该处理获取区域数据错误', async () => {
  105. (areaClient.index.$get as any).mockRejectedValueOnce(new Error('API Error'));
  106. const { result } = renderHook(() => useAreas(), {
  107. wrapper: createWrapper()
  108. });
  109. // Wait for error
  110. await waitFor(() => {
  111. expect(result.current.isError).toBe(true);
  112. });
  113. expect(result.current.error).toBeDefined();
  114. });
  115. it('应该成功创建区域', async () => {
  116. const mockAreaData = {
  117. tenantId: 1,
  118. name: '北京市',
  119. code: '110000',
  120. level: 1,
  121. parentId: null,
  122. isDisabled: 0
  123. };
  124. (areaClient.index.$post as any).mockResolvedValueOnce(createMockResponse(201));
  125. const { result } = renderHook(() => useCreateArea(), {
  126. wrapper: createWrapper()
  127. });
  128. await result.current.mutateAsync(mockAreaData);
  129. expect(areaClient.index.$post).toHaveBeenCalledWith({
  130. json: mockAreaData
  131. });
  132. });
  133. it('应该成功更新区域', async () => {
  134. const mockUpdateData = {
  135. tenantId: 1,
  136. name: '北京市更新',
  137. code: '110000',
  138. level: 1,
  139. parentId: null,
  140. isDisabled: 0
  141. };
  142. (areaClient[':id'].$put as any).mockResolvedValueOnce(createMockResponse(200));
  143. const { result } = renderHook(() => useUpdateArea(), {
  144. wrapper: createWrapper()
  145. });
  146. await result.current.mutateAsync({
  147. id: 1,
  148. data: mockUpdateData
  149. });
  150. expect(areaClient[':id'].$put).toHaveBeenCalledWith({
  151. param: { id: 1 },
  152. json: mockUpdateData
  153. });
  154. });
  155. it('应该成功删除区域', async () => {
  156. (areaClient[':id'].$delete as any).mockResolvedValueOnce(createMockResponse(204));
  157. const { result } = renderHook(() => useDeleteArea(), {
  158. wrapper: createWrapper()
  159. });
  160. await result.current.mutateAsync(1);
  161. expect(areaClient[':id'].$delete).toHaveBeenCalledWith({
  162. param: { id: 1 }
  163. });
  164. });
  165. it('应该成功切换区域状态', async () => {
  166. (areaClient[':id'].$put as any).mockResolvedValueOnce(createMockResponse(200));
  167. const { result } = renderHook(() => useToggleAreaStatus(), {
  168. wrapper: createWrapper()
  169. });
  170. await result.current.mutateAsync({
  171. id: 1,
  172. isDisabled: 1
  173. });
  174. expect(areaClient[':id'].$put).toHaveBeenCalledWith({
  175. param: { id: 1 },
  176. json: { isDisabled: 1 }
  177. });
  178. });
  179. });