mixvideo-v2/apps/desktop/src/__tests__/integration/template-weight-config.e2e....

386 lines
11 KiB
TypeScript

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<typeof TemplateSegmentWeightService>;
const mockAiClassificationService = AiClassificationService as jest.Mocked<typeof AiClassificationService>;
// 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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
onTemplateUpdated={mockOnTemplateUpdated}
/>
);
// 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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
/>
);
// 切换到轨道标签页
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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
/>
);
// 切换到轨道标签页
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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
/>
);
// 切换到轨道标签页并进入编辑模式
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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
/>
);
// 切换到轨道标签页并进入编辑模式
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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
/>
);
// 切换到轨道标签页
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(
<TemplateDetailModal
template={mockTemplate}
onClose={mockOnClose}
/>
);
await user.click(screen.getByText('轨道'));
await waitFor(() => {
// 验证界面在小屏幕下仍然可用
expect(screen.getByText('轨道列表')).toBeInTheDocument();
expect(screen.getByText('批量权重配置')).toBeInTheDocument();
});
});
});