import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import userEvent from '@testing-library/user-event'; import { TemplateDetailModal } from '../../components/template/TemplateDetailModal'; import { TemplateSegmentWeightService } from '../../services/templateSegmentWeightService'; import { AiClassificationService } from '../../services/aiClassificationService'; // Mock Tauri API jest.mock('@tauri-apps/api/core', () => ({ invoke: jest.fn(), })); // Mock services jest.mock('../../services/templateSegmentWeightService'); jest.mock('../../services/aiClassificationService'); const mockTemplateSegmentWeightService = TemplateSegmentWeightService as jest.Mocked; const mockAiClassificationService = AiClassificationService as jest.Mocked; // Mock template data const mockTemplate = { id: 'template_001', name: '测试模板', description: '用于测试权重配置的模板', duration: 30000000, // 30 seconds in microseconds fps: 30, canvas_config: { width: 1920, height: 1080, }, materials: [], tracks: [ { id: 'track_001', template_id: 'template_001', name: '视频轨道1', track_type: 'Video', track_index: 1, segments: [ { id: 'segment_001', track_id: 'track_001', template_material_id: 'material_001', name: '片段1', start_time: 0, end_time: 10000000, duration: 10000000, segment_index: 1, properties: null, matching_rule: { type: 'PriorityOrder', category_ids: ['classification_1', 'classification_2'], }, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, { id: 'segment_002', track_id: 'track_001', template_material_id: 'material_002', name: '片段2', start_time: 10000000, end_time: 20000000, duration: 10000000, segment_index: 2, properties: null, matching_rule: { type: 'PriorityOrder', category_ids: ['classification_1', 'classification_3'], }, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, ], }, ], created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }; const mockAiClassifications = [ { id: 'classification_1', name: '全身', description: '全身照片', prompt: '全身照片的提示词', weight: 80, is_active: true, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, { id: 'classification_2', name: '半身', description: '半身照片', prompt: '半身照片的提示词', weight: 60, is_active: true, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, { id: 'classification_3', name: '特写', description: '特写照片', prompt: '特写照片的提示词', weight: 40, is_active: true, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, ]; describe('Template Weight Configuration E2E Tests', () => { const user = userEvent.setup(); beforeEach(() => { jest.clearAllMocks(); // Setup default mock implementations mockAiClassificationService.getAllClassifications.mockResolvedValue(mockAiClassifications); mockTemplateSegmentWeightService.getSegmentWeightsWithDefaults.mockResolvedValue({ classification_1: 80, classification_2: 60, classification_3: 40, }); mockTemplateSegmentWeightService.hasCustomSegmentWeights.mockResolvedValue(false); mockTemplateSegmentWeightService.setSegmentWeights.mockResolvedValue([]); mockTemplateSegmentWeightService.resetSegmentWeightsToGlobal.mockResolvedValue([]); }); it('完整的权重配置工作流程', async () => { const mockOnClose = jest.fn(); const mockOnTemplateUpdated = jest.fn(); render( ); // 1. 用户打开模板详情页面,切换到轨道标签页 await waitFor(() => { expect(screen.getByText('测试模板')).toBeInTheDocument(); }); // 切换到轨道标签页 await user.click(screen.getByText('轨道')); await waitFor(() => { expect(screen.getByText('轨道列表')).toBeInTheDocument(); }); // 2. 用户查看权重指示器 await waitFor(() => { // 应该显示权重指示器 expect(screen.getByText('全局')).toBeInTheDocument(); }); // 3. 用户点击编辑权重配置 const editButtons = screen.getAllByTitle('编辑权重配置'); await user.click(editButtons[0]); await waitFor(() => { expect(screen.getByText('配置片段权重: 片段1')).toBeInTheDocument(); }); // 4. 用户修改权重值 const sliders = screen.getAllByRole('slider'); expect(sliders.length).toBeGreaterThan(0); // 修改第一个分类的权重 await user.clear(screen.getAllByRole('spinbutton')[0]); await user.type(screen.getAllByRole('spinbutton')[0], '95'); // 5. 用户保存更改 await user.click(screen.getByText('保存')); await waitFor(() => { expect(mockTemplateSegmentWeightService.setSegmentWeights).toHaveBeenCalledWith( 'template_001', 'segment_001', expect.objectContaining({ classification_1: 95, }) ); }); // 6. 验证权重配置已更新 await waitFor(() => { expect(screen.queryByText('保存')).not.toBeInTheDocument(); }); }); it('批量权重配置工作流程', async () => { const mockOnClose = jest.fn(); render( ); // 切换到轨道标签页 await user.click(screen.getByText('轨道')); await waitFor(() => { expect(screen.getByText('批量权重配置')).toBeInTheDocument(); }); // 点击批量权重配置按钮 await user.click(screen.getByText('批量权重配置')); await waitFor(() => { expect(screen.getByText('批量权重配置')).toBeInTheDocument(); expect(screen.getByText('目标片段 (2 个)')).toBeInTheDocument(); }); // 选择自定义权重配置 await user.click(screen.getByLabelText(/自定义权重配置/)); // 修改权重值 const sliders = screen.getAllByRole('slider'); if (sliders.length > 0) { fireEvent.change(sliders[0], { target: { value: '90' } }); } // 执行操作 await user.click(screen.getByText('执行操作')); await waitFor(() => { expect(screen.getByText(/成功处理.*个片段/)).toBeInTheDocument(); }); }); it('重置权重配置工作流程', async () => { // 模拟有自定义权重的情况 mockTemplateSegmentWeightService.hasCustomSegmentWeights.mockResolvedValue(true); const mockOnClose = jest.fn(); render( ); // 切换到轨道标签页 await user.click(screen.getByText('轨道')); await waitFor(() => { expect(screen.getByText('自定义')).toBeInTheDocument(); }); // 点击重置按钮 const resetButtons = screen.getAllByTitle('重置为全局权重'); await user.click(resetButtons[0]); await waitFor(() => { expect(mockTemplateSegmentWeightService.resetSegmentWeightsToGlobal).toHaveBeenCalledWith( 'template_001', 'segment_001' ); }); }); it('权重配置错误处理', async () => { // 模拟服务错误 mockTemplateSegmentWeightService.setSegmentWeights.mockRejectedValue( new Error('保存权重配置失败') ); const mockOnClose = jest.fn(); render( ); // 切换到轨道标签页并进入编辑模式 await user.click(screen.getByText('轨道')); await waitFor(() => { const editButtons = screen.getAllByTitle('编辑权重配置'); return user.click(editButtons[0]); }); // 尝试保存(应该失败) await user.click(screen.getByText('保存')); await waitFor(() => { expect(screen.getByText(/保存权重配置失败/)).toBeInTheDocument(); }); }); it('权重配置验证', async () => { const mockOnClose = jest.fn(); render( ); // 切换到轨道标签页并进入编辑模式 await user.click(screen.getByText('轨道')); await waitFor(() => { const editButtons = screen.getAllByTitle('编辑权重配置'); return user.click(editButtons[0]); }); // 输入无效的权重值 const numberInputs = screen.getAllByRole('spinbutton'); await user.clear(numberInputs[0]); await user.type(numberInputs[0], '150'); // 尝试保存 await user.click(screen.getByText('保存')); await waitFor(() => { expect(screen.getByText(/权重值必须在 0-100 之间/)).toBeInTheDocument(); }); // 验证没有调用保存服务 expect(mockTemplateSegmentWeightService.setSegmentWeights).not.toHaveBeenCalled(); }); it('权重预览功能', async () => { const mockOnClose = jest.fn(); render( ); // 切换到轨道标签页 await user.click(screen.getByText('轨道')); await waitFor(() => { // 应该显示权重预览信息 expect(screen.getByText('全局')).toBeInTheDocument(); }); // 悬停在权重指示器上应该显示详细信息 // 注意:这个测试可能需要根据实际的悬停实现进行调整 }); it('响应式设计测试', async () => { // 测试在不同屏幕尺寸下的权重配置界面 const mockOnClose = jest.fn(); // 模拟小屏幕 Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 768, }); render( ); await user.click(screen.getByText('轨道')); await waitFor(() => { // 验证界面在小屏幕下仍然可用 expect(screen.getByText('轨道列表')).toBeInTheDocument(); expect(screen.getByText('批量权重配置')).toBeInTheDocument(); }); }); });