Pārlūkot izejas kodu

✅ test(activities): 增强活动管理页面测试覆盖率

- 为活动类型选择器添加测试ID并验证交互功能
- 模拟Pointer Events API解决测试环境兼容性问题
- 验证活动类型筛选器选项数量和内容
- 测试活动创建表单中的类型选择交互

✅ test(routes): 完善路线管理页面测试用例

- 为车型筛选器添加测试ID并验证选项内容
- 验证路线创建表单中的活动选择器交互
- 修复重复的Pointer Events API模拟代码
- 增加活动选择下拉菜单的选项验证
yourname 4 mēneši atpakaļ
vecāks
revīzija
4a1dcf505e

+ 1 - 1
src/client/admin/components/ActivityForm.tsx

@@ -94,7 +94,7 @@ export const ActivityForm: React.FC<ActivityFormProps> = ({
                 <FormLabel>活动类型 *</FormLabel>
                 <Select onValueChange={field.onChange} defaultValue={field.value}>
                   <FormControl>
-                    <SelectTrigger>
+                    <SelectTrigger data-testid="activity-type-select">
                       <SelectValue placeholder="选择活动类型" />
                     </SelectTrigger>
                   </FormControl>

+ 36 - 7
tests/integration/client/admin/activities.test.tsx

@@ -94,6 +94,14 @@ describe('ActivitiesPage 集成测试', () => {
 
   beforeEach(() => {
     vi.clearAllMocks();
+
+    // 模拟缺失的 Pointer Events API
+    if (!Element.prototype.hasPointerCapture) {
+      Element.prototype.hasPointerCapture = vi.fn(() => false);
+    }
+    if (!Element.prototype.releasePointerCapture) {
+      Element.prototype.releasePointerCapture = vi.fn();
+    }
   });
 
   it('应该正确渲染活动管理页面标题', async () => {
@@ -147,6 +155,7 @@ describe('ActivitiesPage 集成测试', () => {
   });
 
   it('应该显示活动类型筛选功能', async () => {
+    const user = userEvent.setup();
     render(
       <TestWrapper>
         <ActivitiesPage />
@@ -159,8 +168,15 @@ describe('ActivitiesPage 集成测试', () => {
     });
 
     // 验证类型筛选器存在
-    const typeFilter = screen.getByRole('combobox');
+    const typeFilter = screen.getByTestId('activity-type-filter');
     expect(typeFilter).toBeInTheDocument();
+
+    // 点击Select来展开选项
+    await user.click(typeFilter);
+
+    // 验证筛选选项存在 - 检查选项数量
+    const options = screen.getAllByText(/去程|返程/);
+    expect(options.length).toBeGreaterThanOrEqual(2);
   });
 
   it('应该显示创建活动按钮并打开模态框', async () => {
@@ -291,9 +307,19 @@ describe('ActivitiesPage 集成测试', () => {
     // 验证表单字段存在
     expect(screen.getByLabelText(/活动名称/i)).toBeInTheDocument();
     expect(screen.getByLabelText(/活动描述/i)).toBeInTheDocument();
-    expect(screen.getByLabelText(/活动类型/i)).toBeInTheDocument();
     expect(screen.getByLabelText(/开始日期/i)).toBeInTheDocument();
     expect(screen.getByLabelText(/结束日期/i)).toBeInTheDocument();
+
+    // 验证活动类型Select存在并测试点击交互
+    const activityTypeSelect = screen.getByTestId('activity-type-select');
+    expect(activityTypeSelect).toBeInTheDocument();
+
+    // 点击Select来展开选项
+    await user.click(activityTypeSelect);
+
+    // 验证活动类型选项存在 - 检查选项数量
+    const activityOptions = screen.getAllByText(/去程活动|返程活动/);
+    expect(activityOptions.length).toBeGreaterThanOrEqual(2);
   });
 
   it('应该处理启用/禁用活动操作', async () => {
@@ -364,13 +390,16 @@ describe('ActivitiesPage 集成测试', () => {
       expect(screen.getByText('北京去程活动')).toBeInTheDocument();
     });
 
-    // 验证类型筛选器存在,但不直接点击避免事件错误
-    const typeFilter = screen.getByRole('combobox');
+    // 验证类型筛选器存在
+    const typeFilter = screen.getByTestId('activity-type-filter');
     expect(typeFilter).toBeInTheDocument();
 
-    // 验证筛选选项存在
-    expect(screen.getByText('去程')).toBeInTheDocument();
-    expect(screen.getByText('返程')).toBeInTheDocument();
+    // 点击Select来展开选项
+    await user.click(typeFilter);
+
+    // 验证筛选选项存在 - 检查选项数量
+    const options = screen.getAllByText(/去程|返程/);
+    expect(options.length).toBeGreaterThanOrEqual(2);
   });
 
   it('应该处理API错误场景', async () => {

+ 57 - 11
tests/integration/client/admin/routes.test.tsx

@@ -17,8 +17,33 @@ vi.mock('next-themes', () => ({
   }),
 }));
 
-// Mock API 客户端
+// Mock activityClient for ActivitySelect component
 vi.mock('@/client/api', () => ({
+  activityClient: {
+    $get: vi.fn().mockResolvedValue({
+      status: 200,
+      ok: true,
+      json: async () => ({
+        data: [
+          {
+            id: 1,
+            name: '北京去程活动',
+            type: 'departure'
+          },
+          {
+            id: 2,
+            name: '上海返程活动',
+            type: 'return'
+          }
+        ],
+        pagination: {
+          total: 2,
+          current: 1,
+          pageSize: 50
+        }
+      })
+    })
+  },
   routeClient: {
     $get: vi.fn().mockResolvedValue({
       status: 200,
@@ -126,6 +151,14 @@ describe('RoutesPage 集成测试', () => {
 
   beforeEach(() => {
     vi.clearAllMocks();
+
+    // 模拟缺失的 Pointer Events API
+    if (!Element.prototype.hasPointerCapture) {
+      Element.prototype.hasPointerCapture = vi.fn(() => false);
+    }
+    if (!Element.prototype.releasePointerCapture) {
+      Element.prototype.releasePointerCapture = vi.fn();
+    }
   });
 
   it('应该正确渲染路线管理页面标题', async () => {
@@ -179,6 +212,7 @@ describe('RoutesPage 集成测试', () => {
   });
 
   it('应该显示车型筛选功能', async () => {
+    const user = userEvent.setup();
     render(
       <TestWrapper>
         <RoutesPage />
@@ -191,8 +225,16 @@ describe('RoutesPage 集成测试', () => {
     });
 
     // 验证车型筛选器存在
-    const vehicleTypeFilter = screen.getByRole('combobox');
+    const vehicleTypeFilter = screen.getByTestId('route-vehicle-type-filter');
     expect(vehicleTypeFilter).toBeInTheDocument();
+
+    // 点击Select来展开选项
+    await user.click(vehicleTypeFilter);
+
+    // 验证筛选选项存在
+    expect(screen.getByText('大巴')).toBeInTheDocument();
+    expect(screen.getByText('中巴')).toBeInTheDocument();
+    expect(screen.getByText('小车')).toBeInTheDocument();
   });
 
   it('应该显示创建路线按钮并打开模态框', async () => {
@@ -341,7 +383,19 @@ describe('RoutesPage 集成测试', () => {
     expect(screen.getByTestId('price-input')).toBeInTheDocument();
     expect(screen.getByTestId('seat-count-input')).toBeInTheDocument();
     expect(screen.getByTestId('available-seats-input')).toBeInTheDocument();
-    expect(screen.getByTestId('activity-select')).toBeInTheDocument();
+
+    // 验证ActivitySelect组件存在并测试点击交互
+    const activitySelect = screen.getByTestId('activity-select');
+    expect(activitySelect).toBeInTheDocument();
+
+    // 点击ActivitySelect来展开选项
+    await user.click(activitySelect);
+
+    // 等待活动选项加载并验证选项存在
+    await waitFor(() => {
+      expect(screen.getByText('北京去程活动 (去程)')).toBeInTheDocument();
+      expect(screen.getByText('上海返程活动 (返程)')).toBeInTheDocument();
+    });
   });
 
   it('应该处理启用/禁用路线操作', async () => {
@@ -403,14 +457,6 @@ describe('RoutesPage 集成测试', () => {
   it('应该处理车型筛选', async () => {
     const user = userEvent.setup();
 
-    // 在测试前模拟缺失的 Pointer Events API
-    if (!Element.prototype.hasPointerCapture) {
-      Element.prototype.hasPointerCapture = vi.fn(() => false);
-    }
-    if (!Element.prototype.releasePointerCapture) {
-      Element.prototype.releasePointerCapture = vi.fn();
-    }
-
     render(
       <TestWrapper>
         <RoutesPage />