Quellcode durchsuchen

📦 build(area-management-ui): 移除测试工具包导出

- 从package.json的exports字段中移除`./test-utils`路径,使其不再对外暴露
- 从files字段中移除`test/utils`目录,发布包将不再包含测试工具文件
- 删除整个`test/utils`目录,包括TestWrapper组件、mock数据、mock客户端及使用示例
- 更新测试setup文件中的ResizeObserver mock以修复Select组件测试问题
- 移除过时的IntersectionObserver mock并添加Element.scrollIntoView mock
yourname vor 2 Wochen
Ursprung
Commit
2b78ed58fb

+ 1 - 7
packages/area-management-ui/package.json

@@ -25,16 +25,10 @@
       "types": "./src/api/index.ts",
       "import": "./src/api/index.ts",
       "require": "./src/api/index.ts"
-    },
-    "./test-utils": {
-      "types": "./test/utils/index.ts",
-      "import": "./test/utils/index.ts",
-      "require": "./test/utils/index.ts"
     }
   },
   "files": [
-    "src",
-    "test/utils"
+    "src"
   ],
   "scripts": {
     "build": "unbuild",

+ 0 - 43
packages/area-management-ui/test/utils/TestWrapper.tsx

@@ -1,43 +0,0 @@
-/**
- * 测试包装组件
- * 提供测试环境所需的Provider包装
- */
-
-import React from 'react';
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { BrowserRouter } from 'react-router';
-
-interface TestWrapperProps {
-  children: React.ReactNode;
-  queryClient?: QueryClient;
-  withRouter?: boolean;
-}
-
-const TestWrapper: React.FC<TestWrapperProps> = ({
-  children,
-  queryClient,
-  withRouter = true,
-}) => {
-  const testQueryClient = queryClient || new QueryClient({
-    defaultOptions: {
-      queries: {
-        retry: false,
-        gcTime: 0,
-      },
-    },
-  });
-
-  const content = (
-    <QueryClientProvider client={testQueryClient}>
-      {children}
-    </QueryClientProvider>
-  );
-
-  if (withRouter) {
-    return <BrowserRouter>{content}</BrowserRouter>;
-  }
-
-  return content;
-};
-
-export default TestWrapper;

+ 0 - 13
packages/area-management-ui/test/utils/index.ts

@@ -1,13 +0,0 @@
-/**
- * area-management-ui 测试工具包
- * 提供可复用的测试工具,供其他包在测试中使用
- */
-
-export * from './mockAreaData';
-export * from './mockAreaClient';
-
-// 常用测试工具
-export { default as TestWrapper } from './TestWrapper';
-
-// 类型导出
-export type { AreaTestData } from './mockAreaData';

+ 0 - 212
packages/area-management-ui/test/utils/mockAreaClient.ts

@@ -1,212 +0,0 @@
-/**
- * areaClient 测试mock工具
- * 用于在测试中模拟areaClient API调用
- */
-
-import { vi } from 'vitest';
-import { mockAllAreas, filterAreas, getPaginatedData, type AreaTestData } from './mockAreaData';
-
-// 完整的mock响应对象 - 按照用户UI包规范
-export const createMockResponse = (status: number, data?: any) => ({
-  status,
-  ok: status >= 200 && status < 300,
-  body: null,
-  bodyUsed: false,
-  statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
-  headers: new Headers(),
-  url: '',
-  redirected: false,
-  type: 'basic' as ResponseType,
-  json: async () => data || {},
-  text: async () => '',
-  blob: async () => new Blob(),
-  arrayBuffer: async () => new ArrayBuffer(0),
-  formData: async () => new FormData(),
-  clone: function() { return this; }
-});
-
-// 创建mock的areaClient
-export const createMockAreaClient = (customData?: AreaTestData[]) => {
-  const areas = customData || mockAllAreas;
-
-  // 模拟 $get 方法
-  const mockGet = vi.fn(async (options?: { query?: any }) => {
-    const { query = {} } = options || {};
-    const { page = 1, pageSize = 10, filters = '{}', sortBy = 'id', sortOrder = 'ASC' } = query;
-
-    // 解析filters
-    let parsedFilters = {};
-    try {
-      parsedFilters = JSON.parse(filters);
-    } catch {
-      parsedFilters = {};
-    }
-
-    // 筛选数据
-    let filteredAreas = [...areas];
-
-    // 应用筛选条件
-    if (parsedFilters) {
-      filteredAreas = filterAreas(areas, parsedFilters);
-    }
-
-    // 排序
-    filteredAreas.sort((a, b) => {
-      const aValue = a[sortBy as keyof AreaTestData];
-      const bValue = b[sortBy as keyof AreaTestData];
-
-      if (typeof aValue === 'number' && typeof bValue === 'number') {
-        return sortOrder === 'ASC' ? aValue - bValue : bValue - aValue;
-      }
-
-      if (typeof aValue === 'string' && typeof bValue === 'string') {
-        return sortOrder === 'ASC'
-          ? aValue.localeCompare(bValue)
-          : bValue.localeCompare(aValue);
-      }
-
-      return 0;
-    });
-
-    // 分页
-    const paginated = getPaginatedData(filteredAreas, page, pageSize);
-
-    return Promise.resolve(createMockResponse(200, paginated));
-  });
-
-  // 模拟 $post 方法
-  const mockPost = vi.fn(async (options?: { json?: any }) => {
-    const { json = {} } = options || {};
-    const newId = Math.max(...areas.map(a => a.id)) + 1;
-    const newArea: AreaTestData = {
-      id: newId,
-      name: json.name || '新地区',
-      level: json.level || 1,
-      parentId: json.parentId,
-      isDisabled: json.isDisabled || 0,
-      sort: json.sort || 0,
-    };
-
-    areas.push(newArea);
-
-    return Promise.resolve(createMockResponse(201, newArea));
-  });
-
-  // 模拟 $put 方法
-  const mockPut = vi.fn(async (options?: { param?: any; json?: any }) => {
-    const { param = {}, json = {} } = options || {};
-    const id = param.id ? parseInt(param.id) : 0;
-
-    const index = areas.findIndex(area => area.id === id);
-    if (index === -1) {
-      return Promise.resolve(createMockResponse(404, { error: '地区不存在' }));
-    }
-
-    areas[index] = { ...areas[index], ...json };
-
-    return Promise.resolve(createMockResponse(200, areas[index]));
-  });
-
-  // 模拟 $delete 方法
-  const mockDelete = vi.fn(async (options?: { param?: any }) => {
-    const { param = {} } = options || {};
-    const id = param.id ? parseInt(param.id) : 0;
-
-    const index = areas.findIndex(area => area.id === id);
-    if (index === -1) {
-      return Promise.resolve(createMockResponse(404, { error: '地区不存在' }));
-    }
-
-    areas.splice(index, 1);
-
-    return Promise.resolve(createMockResponse(204));
-  });
-
-  return {
-    index: {
-      $get: mockGet,
-      $post: mockPost,
-    },
-    ':id': {
-      $put: mockPut,
-      $delete: mockDelete,
-    },
-  };
-};
-
-// 创建mock的areaClientManager
-export const createMockAreaClientManager = (customData?: AreaTestData[]) => {
-  const mockClient = createMockAreaClient(customData);
-
-  return {
-    getInstance: vi.fn(() => ({
-      get: vi.fn(() => mockClient),
-      reset: vi.fn(),
-    })),
-    get: vi.fn(() => mockClient),
-    reset: vi.fn(),
-  };
-};
-
-// 完整的mock配置(用于vi.mock)
-export const createAreaClientMock = (customData?: AreaTestData[]) => {
-  const mockClient = createMockAreaClient(customData);
-  const mockManager = createMockAreaClientManager(customData);
-
-  return {
-    areaClient: mockClient,
-    areaClientManager: mockManager,
-  };
-};
-
-// 预设的mock配置(快速使用)
-export const presetMocks = {
-  // 基本成功mock
-  success: () => createAreaClientMock(),
-
-  // 空数据mock
-  empty: () => createAreaClientMock([]),
-
-  // 错误mock
-  error: (errorType: 'network' | 'server' | 'notFound' = 'server') => {
-    const mockClient = {
-      index: {
-        $get: vi.fn(() => {
-          if (errorType === 'network') {
-            return Promise.reject(new Error('Network Error'));
-          }
-          return Promise.resolve(createMockResponse(500, { error: '服务器错误' }));
-        }),
-        $post: vi.fn(() => Promise.resolve(createMockResponse(500, { error: '创建失败' }))),
-      },
-      ':id': {
-        $put: vi.fn(() => {
-          if (errorType === 'notFound') {
-            return Promise.resolve(createMockResponse(404, { error: '地区不存在' }));
-          }
-          return Promise.resolve(createMockResponse(500, { error: '更新失败' }));
-        }),
-        $delete: vi.fn(() => {
-          if (errorType === 'notFound') {
-            return Promise.resolve(createMockResponse(404, { error: '地区不存在' }));
-          }
-          return Promise.resolve(createMockResponse(500, { error: '删除失败' }));
-        }),
-      },
-    };
-
-    const mockManager = {
-      getInstance: vi.fn(() => ({
-        get: vi.fn(() => mockClient),
-        reset: vi.fn(),
-      })),
-      get: vi.fn(() => mockClient),
-      reset: vi.fn(),
-    };
-
-    return {
-      areaClient: mockClient,
-      areaClientManager: mockManager,
-    };
-  },
-};

+ 0 - 83
packages/area-management-ui/test/utils/mockAreaData.ts

@@ -1,83 +0,0 @@
-/**
- * 地区测试数据
- * 用于在测试中模拟地区数据
- */
-
-export interface AreaTestData {
-  id: number;
-  name: string;
-  level: number;
-  parentId?: number;
-  isDisabled?: number;
-  sort?: number;
-}
-
-// 省份数据(level: 1)
-export const mockProvinces: AreaTestData[] = [
-  { id: 1, name: '北京市', level: 1, isDisabled: 0, sort: 1 },
-  { id: 2, name: '上海市', level: 1, isDisabled: 0, sort: 2 },
-  { id: 3, name: '广东省', level: 1, isDisabled: 0, sort: 3 },
-  { id: 4, name: '江苏省', level: 1, isDisabled: 0, sort: 4 },
-  { id: 5, name: '浙江省', level: 1, isDisabled: 0, sort: 5 },
-];
-
-// 城市数据(level: 2)
-export const mockCities: AreaTestData[] = [
-  { id: 11, name: '北京市', level: 2, parentId: 1, isDisabled: 0, sort: 1 },
-  { id: 12, name: '上海市', level: 2, parentId: 2, isDisabled: 0, sort: 1 },
-  { id: 13, name: '广州市', level: 2, parentId: 3, isDisabled: 0, sort: 1 },
-  { id: 14, name: '深圳市', level: 2, parentId: 3, isDisabled: 0, sort: 2 },
-  { id: 15, name: '南京市', level: 2, parentId: 4, isDisabled: 0, sort: 1 },
-  { id: 16, name: '苏州市', level: 2, parentId: 4, isDisabled: 0, sort: 2 },
-  { id: 17, name: '杭州市', level: 2, parentId: 5, isDisabled: 0, sort: 1 },
-  { id: 18, name: '宁波市', level: 2, parentId: 5, isDisabled: 0, sort: 2 },
-];
-
-// 区县数据(level: 3)
-export const mockDistricts: AreaTestData[] = [
-  { id: 101, name: '东城区', level: 3, parentId: 11, isDisabled: 0, sort: 1 },
-  { id: 102, name: '西城区', level: 3, parentId: 11, isDisabled: 0, sort: 2 },
-  { id: 103, name: '黄浦区', level: 3, parentId: 12, isDisabled: 0, sort: 1 },
-  { id: 104, name: '徐汇区', level: 3, parentId: 12, isDisabled: 0, sort: 2 },
-  { id: 105, name: '天河区', level: 3, parentId: 13, isDisabled: 0, sort: 1 },
-  { id: 106, name: '越秀区', level: 3, parentId: 13, isDisabled: 0, sort: 2 },
-  { id: 107, name: '福田区', level: 3, parentId: 14, isDisabled: 0, sort: 1 },
-  { id: 108, name: '南山区', level: 3, parentId: 14, isDisabled: 0, sort: 2 },
-];
-
-// 所有地区数据
-export const mockAllAreas: AreaTestData[] = [
-  ...mockProvinces,
-  ...mockCities,
-  ...mockDistricts,
-];
-
-// 根据条件筛选地区数据
-export const filterAreas = (
-  areas: AreaTestData[],
-  filters?: { level?: number; parentId?: number; isDisabled?: number }
-): AreaTestData[] => {
-  return areas.filter(area => {
-    if (filters?.level !== undefined && area.level !== filters.level) return false;
-    if (filters?.parentId !== undefined && area.parentId !== filters.parentId) return false;
-    if (filters?.isDisabled !== undefined && area.isDisabled !== filters.isDisabled) return false;
-    return true;
-  });
-};
-
-// 获取分页数据
-export const getPaginatedData = (
-  areas: AreaTestData[],
-  page: number = 1,
-  pageSize: number = 10
-) => {
-  const start = (page - 1) * pageSize;
-  const end = start + pageSize;
-  return {
-    data: areas.slice(start, end),
-    total: areas.length,
-    page,
-    pageSize,
-    totalPages: Math.ceil(areas.length / pageSize),
-  };
-};

+ 0 - 120
packages/area-management-ui/test/utils/usage-example.ts

@@ -1,120 +0,0 @@
-/**
- * 测试工具使用示例
- * 展示如何在其他包中使用 area-management-ui 的测试工具
- */
-
-import { vi } from 'vitest';
-
-// 示例1:基本使用
-export const example1 = `
-// 在残疾人管理UI包的测试中
-import { createAreaClientMock, mockAreaData } from '@d8d/area-management-ui/test-utils';
-
-// Mock areaClient API
-vi.mock('@d8d/area-management-ui/api', () => createAreaClientMock());
-
-// 或者使用预设数据
-vi.mock('@d8d/area-management-ui/api', () => createAreaClientMock(mockAreaData.mockAllAreas));
-`;
-
-// 示例2:使用预设mock
-export const example2 = `
-import { presetMocks } from '@d8d/area-management-ui/test-utils';
-
-// 使用成功mock
-vi.mock('@d8d/area-management-ui/api', () => presetMocks.success());
-
-// 使用空数据mock
-vi.mock('@d8d/area-management-ui/api', () => presetMocks.empty());
-
-// 使用错误mock
-vi.mock('@d8d/area-management-ui/api', () => presetMocks.error('network'));
-`;
-
-// 示例3:完整测试示例
-export const example3 = `
-import { describe, it, expect, vi, beforeEach } from 'vitest';
-import { render, screen } from '@testing-library/react';
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { createAreaClientMock, TestWrapper } from '@d8d/area-management-ui/test-utils';
-import YourComponent from './YourComponent';
-
-// Mock areaClient
-vi.mock('@d8d/area-management-ui/api', () => createAreaClientMock());
-
-describe('YourComponent', () => {
-  beforeEach(() => {
-    vi.clearAllMocks();
-  });
-
-  it('应该正确渲染', () => {
-    render(
-      <TestWrapper>
-        <YourComponent />
-      </TestWrapper>
-    );
-
-    expect(screen.getByText('Some content')).toBeInTheDocument();
-  });
-});
-`;
-
-// 示例4:在残疾人管理UI包中的实际使用
-export const disabilityManagementExample = `
-// 文件:allin-packages/disability-person-management-ui/tests/integration/disability-person.integration.test.tsx
-
-import { createAreaClientMock } from '@d8d/area-management-ui/test-utils';
-
-// 替换原有的复杂mock
-// 原来的:
-// vi.mock('@d8d/area-management-ui/components', () => ({
-//   AreaSelect: vi.fn(...),
-//   AreaSelectForm: vi.fn(...),
-// }));
-
-// 现在的:
-vi.mock('@d8d/area-management-ui/api', () => createAreaClientMock());
-
-// 注意:现在我们不需要mock UI组件了!
-// 可以直接使用真实的 AreaSelect 和 AreaSelectForm 组件
-// 因为它们会使用我们mock的API
-`;
-
-// 示例5:在强权管理UI包中的使用
-export const orderManagementExample = `
-// 文件:allin-packages/order-management-ui/tests/integration/order.integration.test.tsx
-
-import { createAreaClientMock } from '@d8d/area-management-ui/test-utils';
-
-// 替换原有的mock
-// 原来的:
-// vi.mock('@d8d/area-management-ui', () => ({
-//   AreaSelect: vi.fn(({ value, onChange }) => (...)),
-// }));
-
-// 现在的:
-vi.mock('@d8d/area-management-ui/api', () => createAreaClientMock());
-
-// 现在可以直接使用真实的 AreaSelect 组件
-// 组件会从mock的API获取数据
-`;
-
-// 优势总结
-export const advantages = `
-## 使用测试工具的优势
-
-1. **一致性**:所有包使用相同的mock逻辑
-2. **维护性**:mock逻辑集中在一处,易于更新
-3. **真实性**:使用真实组件,测试更接近实际使用
-4. **简化测试**:减少重复的mock代码
-5. **类型安全**:提供完整的TypeScript类型支持
-6. **灵活性**:支持自定义数据和错误场景
-
-## 迁移步骤
-
-1. 安装或更新 area-management-ui 包
-2. 导入测试工具:import { createAreaClientMock } from '@d8d/area-management-ui/test-utils'
-3. 替换原有的 areaClient mock
-4. 移除对 UI 组件的 mock(AreaSelect, AreaSelectForm)
-5. 运行测试,确保一切正常
-`;

+ 14 - 24
packages/area-management-ui/tests/setup.ts

@@ -8,36 +8,26 @@ Object.defineProperty(window, 'matchMedia', {
     matches: false,
     media: query,
     onchange: null,
-    addListener: vi.fn(), // deprecated
-    removeListener: vi.fn(), // deprecated
+    addListener: vi.fn(),
+    removeListener: vi.fn(),
     addEventListener: vi.fn(),
     removeEventListener: vi.fn(),
     dispatchEvent: vi.fn(),
   })),
 });
 
-// Mock ResizeObserver
-global.ResizeObserver = class MockResizeObserver {
-  constructor(callback: ResizeObserverCallback) {
-    // Store callback for testing
-    (this as any).callback = callback;
+// Mock ResizeObserver - 需要调用callback以便Select组件正常工作
+global.ResizeObserver = class ResizeObserver {
+  cb: any;
+  constructor(cb: any) {
+    this.cb = cb;
   }
-  observe = vi.fn();
-  unobserve = vi.fn();
-  disconnect = vi.fn();
+  observe() {
+    this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]);
+  }
+  unobserve() {}
+  disconnect() {}
 };
 
-// Mock IntersectionObserver
-global.IntersectionObserver = class MockIntersectionObserver {
-  constructor(callback: IntersectionObserverCallback) {
-    // Store callback for testing
-    (this as any).callback = callback;
-  }
-  observe = vi.fn();
-  unobserve = vi.fn();
-  disconnect = vi.fn();
-  root: Element | null = null;
-  rootMargin: string = '';
-  thresholds: ReadonlyArray<number> = [];
-  takeRecords = vi.fn();
-};
+// Mock Element.scrollIntoView 避免shadcn/ui Select组件错误
+Element.prototype.scrollIntoView = vi.fn();