基于项目需求文档(PRD.md, FeatureSummary.md, DevelopmentPlan.md, UIDesign.md, User_Role_Interfaces.md)编写的 TDD 测试用例。 后端测试 (Python/pytest): - 单元测试: rule_engine, brief_parser, timestamp_alignment, video_auditor, validators - 集成测试: API Brief, Video, Review 端点 - AI 模块测试: ASR, OCR, Logo 检测服务 - 全局 fixtures 和 pytest 配置 前端测试 (TypeScript/Vitest): - 工具函数测试: utils.test.ts - 组件测试: Button, VideoPlayer, ViolationList - Hooks 测试: useVideoAudit, useVideoPlayer, useAppeal - MSW mock handlers 配置 E2E 测试 (Playwright): - 认证流程测试 - 视频上传流程测试 - 视频审核流程测试 - 申诉流程测试 所有测试当前使用 pytest.skip() / it.skip() 作为占位符, 遵循 TDD 红灯阶段 - 等待实现代码后运行。 验收标准覆盖: - ASR WER ≤ 10% - OCR 准确率 ≥ 95% - Logo F1 ≥ 0.85 - 时间戳误差 ≤ 0.5s - 频次统计准确率 ≥ 95% Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
155 lines
3.6 KiB
TypeScript
155 lines
3.6 KiB
TypeScript
/**
|
|
* MSW 请求处理器
|
|
*
|
|
* 模拟后端 API 响应
|
|
*/
|
|
|
|
// import { http, HttpResponse } from 'msw'
|
|
|
|
// API Base URL
|
|
// const API_BASE = '/api/v1'
|
|
|
|
// 模拟用户数据
|
|
export const mockUsers = {
|
|
creator: {
|
|
id: 'user_creator_001',
|
|
email: 'creator@test.com',
|
|
name: '测试达人',
|
|
role: 'creator',
|
|
appeal_tokens: 3,
|
|
},
|
|
agency: {
|
|
id: 'user_agency_001',
|
|
email: 'agency@test.com',
|
|
name: '测试 Agency',
|
|
role: 'agency',
|
|
},
|
|
brand: {
|
|
id: 'user_brand_001',
|
|
email: 'brand@test.com',
|
|
name: '测试品牌方',
|
|
role: 'brand',
|
|
},
|
|
admin: {
|
|
id: 'user_admin_001',
|
|
email: 'admin@test.com',
|
|
name: '系统管理员',
|
|
role: 'admin',
|
|
},
|
|
}
|
|
|
|
// 模拟视频数据
|
|
export const mockVideos = [
|
|
{
|
|
id: 'video_001',
|
|
title: '测试视频 1',
|
|
status: 'pending_review',
|
|
creator_id: 'user_creator_001',
|
|
task_id: 'task_001',
|
|
duration_ms: 60000,
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
},
|
|
{
|
|
id: 'video_002',
|
|
title: '测试视频 2',
|
|
status: 'passed',
|
|
creator_id: 'user_creator_001',
|
|
task_id: 'task_001',
|
|
duration_ms: 120000,
|
|
created_at: '2024-01-02T00:00:00Z',
|
|
},
|
|
]
|
|
|
|
// 模拟违规数据
|
|
export const mockViolations = [
|
|
{
|
|
id: 'vio_001',
|
|
video_id: 'video_001',
|
|
type: 'prohibited_word',
|
|
content: '最好的',
|
|
timestamp_start: 5.0,
|
|
timestamp_end: 5.5,
|
|
severity: 'high',
|
|
source: 'ai',
|
|
},
|
|
{
|
|
id: 'vio_002',
|
|
video_id: 'video_001',
|
|
type: 'competitor_logo',
|
|
content: 'CompetitorBrand',
|
|
timestamp_start: 10.0,
|
|
timestamp_end: 15.0,
|
|
severity: 'medium',
|
|
source: 'ai',
|
|
},
|
|
]
|
|
|
|
// 模拟 Brief 数据
|
|
export const mockBriefs = {
|
|
brief_001: {
|
|
id: 'brief_001',
|
|
task_id: 'task_001',
|
|
selling_points: [
|
|
{ text: '24小时持妆', priority: 'high' },
|
|
{ text: '天然成分', priority: 'medium' },
|
|
],
|
|
forbidden_words: ['药用', '治疗', '最好的'],
|
|
timing_requirements: [
|
|
{ type: 'product_visible', min_duration_seconds: 5 },
|
|
{ type: 'brand_mention', min_frequency: 3 },
|
|
],
|
|
brand_tone: {
|
|
style: ['年轻活力', '专业可信'],
|
|
target_audience: '18-35岁女性',
|
|
},
|
|
platform: 'douyin',
|
|
region: 'mainland_china',
|
|
},
|
|
}
|
|
|
|
// TODO: 实现 MSW handlers
|
|
// export const handlers = [
|
|
// // 认证相关
|
|
// http.post(`${API_BASE}/auth/login`, async ({ request }) => {
|
|
// const body = await request.json()
|
|
// // 模拟登录逻辑
|
|
// return HttpResponse.json({
|
|
// access_token: 'mock_token',
|
|
// user: mockUsers.creator,
|
|
// })
|
|
// }),
|
|
//
|
|
// // 视频相关
|
|
// http.get(`${API_BASE}/videos`, () => {
|
|
// return HttpResponse.json({
|
|
// items: mockVideos,
|
|
// total: mockVideos.length,
|
|
// page: 1,
|
|
// page_size: 10,
|
|
// })
|
|
// }),
|
|
//
|
|
// http.get(`${API_BASE}/videos/:videoId`, ({ params }) => {
|
|
// const video = mockVideos.find(v => v.id === params.videoId)
|
|
// if (!video) {
|
|
// return new HttpResponse(null, { status: 404 })
|
|
// }
|
|
// return HttpResponse.json(video)
|
|
// }),
|
|
//
|
|
// // 审核相关
|
|
// http.get(`${API_BASE}/videos/:videoId/violations`, ({ params }) => {
|
|
// const violations = mockViolations.filter(v => v.video_id === params.videoId)
|
|
// return HttpResponse.json({ violations })
|
|
// }),
|
|
//
|
|
// // Brief 相关
|
|
// http.get(`${API_BASE}/briefs/:briefId`, ({ params }) => {
|
|
// const brief = mockBriefs[params.briefId as keyof typeof mockBriefs]
|
|
// if (!brief) {
|
|
// return new HttpResponse(null, { status: 404 })
|
|
// }
|
|
// return HttpResponse.json(brief)
|
|
// }),
|
|
// ]
|