386 lines
11 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
});
|