merchant-selector.integration.test.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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 { MerchantSelector } from '../../src/components/MerchantSelector';
  5. import { merchantClient } from '../../src/api/merchantClient';
  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/merchantClient', () => {
  26. const mockMerchantClient = {
  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 mockMerchantClientManager = {
  34. get: vi.fn(() => mockMerchantClient),
  35. };
  36. return {
  37. merchantClientManager: mockMerchantClientManager,
  38. merchantClient: mockMerchantClient,
  39. };
  40. });
  41. const createTestQueryClient = () =>
  42. new QueryClient({
  43. defaultOptions: {
  44. queries: {
  45. retry: false,
  46. },
  47. },
  48. });
  49. const renderWithProviders = (component: React.ReactElement) => {
  50. const queryClient = createTestQueryClient();
  51. return render(
  52. <QueryClientProvider client={queryClient}>
  53. {component}
  54. </QueryClientProvider>
  55. );
  56. };
  57. describe('MerchantSelector', () => {
  58. beforeEach(() => {
  59. vi.clearAllMocks();
  60. });
  61. it('应该渲染商户选择器', () => {
  62. renderWithProviders(<MerchantSelector testId="merchant-selector" />);
  63. const selectTrigger = screen.getByTestId('merchant-selector');
  64. expect(selectTrigger).toBeInTheDocument();
  65. });
  66. it('应该显示自定义占位符', () => {
  67. renderWithProviders(
  68. <MerchantSelector
  69. placeholder="请选择商户"
  70. testId="merchant-selector"
  71. />
  72. );
  73. const selectTrigger = screen.getByTestId('merchant-selector');
  74. expect(selectTrigger).toHaveTextContent('请选择商户');
  75. });
  76. it('应该调用API获取商户列表', async () => {
  77. const mockMerchants = [
  78. { id: 1, name: '商户A' },
  79. { id: 2, name: '商户B' }
  80. ];
  81. (merchantClient.$get as any).mockResolvedValueOnce(
  82. createMockResponse(200, {
  83. data: mockMerchants,
  84. pagination: { total: 2, page: 1, pageSize: 100 }
  85. })
  86. );
  87. renderWithProviders(<MerchantSelector testId="merchant-selector" />);
  88. await waitFor(() => {
  89. expect(merchantClient.$get).toHaveBeenCalledWith({
  90. query: { page: 1, pageSize: 100 }
  91. });
  92. });
  93. });
  94. it('应该显示商户列表', async () => {
  95. const mockMerchants = [
  96. { id: 1, name: '商户A' },
  97. { id: 2, name: '商户B' }
  98. ];
  99. (merchantClient.$get as any).mockResolvedValueOnce(
  100. createMockResponse(200, {
  101. data: mockMerchants,
  102. pagination: { total: 2, page: 1, pageSize: 100 }
  103. })
  104. );
  105. renderWithProviders(<MerchantSelector testId="merchant-selector" />);
  106. await waitFor(() => {
  107. expect(merchantClient.$get).toHaveBeenCalledWith({
  108. query: { page: 1, pageSize: 100 }
  109. });
  110. });
  111. // 验证API调用,不测试下拉菜单的UI交互
  112. expect(merchantClient.$get).toHaveBeenCalledTimes(1);
  113. });
  114. it('应该处理API错误', async () => {
  115. (merchantClient.$get as any).mockRejectedValueOnce(new Error('API错误'));
  116. renderWithProviders(<MerchantSelector testId="merchant-selector" />);
  117. // 验证组件渲染
  118. const selectTrigger = screen.getByTestId('merchant-selector');
  119. expect(selectTrigger).toBeInTheDocument();
  120. // 等待API调用完成
  121. await waitFor(() => {
  122. expect(merchantClient.$get).toHaveBeenCalled();
  123. });
  124. });
  125. it('应该支持禁用状态', () => {
  126. renderWithProviders(
  127. <MerchantSelector
  128. disabled={true}
  129. testId="merchant-selector"
  130. />
  131. );
  132. const selectTrigger = screen.getByTestId('merchant-selector');
  133. expect(selectTrigger).toBeDisabled();
  134. });
  135. it('应该支持值选择', async () => {
  136. const mockMerchants = [
  137. { id: 1, name: '商户A' },
  138. { id: 2, name: '商户B' }
  139. ];
  140. (merchantClient.$get as any).mockResolvedValueOnce(
  141. createMockResponse(200, {
  142. data: mockMerchants,
  143. pagination: { total: 2, page: 1, pageSize: 100 }
  144. })
  145. );
  146. const mockOnChange = vi.fn();
  147. renderWithProviders(
  148. <MerchantSelector
  149. onChange={mockOnChange}
  150. testId="merchant-selector"
  151. />
  152. );
  153. await waitFor(() => {
  154. expect(merchantClient.$get).toHaveBeenCalledWith({
  155. query: { page: 1, pageSize: 100 }
  156. });
  157. });
  158. // 验证API调用,不测试下拉菜单的UI交互
  159. expect(merchantClient.$get).toHaveBeenCalledTimes(1);
  160. });
  161. });