videos1.0/frontend/e2e/tests/appeal.spec.ts
Your Name 040aada160 feat: 添加全面的 TDD 测试套件框架
基于项目需求文档(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>
2026-02-02 17:22:24 +08:00

211 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 申诉流程 E2E 测试
*
* TDD 测试用例 - 测试达人申诉和审核员处理申诉的流程
*
* 用户流程参考User_Role_Interfaces.md
*/
import { test, expect } from '@playwright/test'
test.describe('Creator Appeal Flow', () => {
test.beforeEach(async ({ page }) => {
// 以达人身份登录
// await page.goto('/login')
// await page.getByPlaceholder('邮箱').fill('creator@example.com')
// await page.getByPlaceholder('密码').fill('password123')
// await page.getByRole('button', { name: '登录' }).click()
// await page.waitForURL('/dashboard')
})
test.skip('should display appeal tokens', async ({ page }) => {
// await page.goto('/dashboard')
//
// // 验证显示申诉令牌数量
// await expect(page.getByTestId('appeal-tokens')).toBeVisible()
// await expect(page.getByText('剩余申诉次数3')).toBeVisible()
})
test.skip('should open appeal form from rejected video', async ({ page }) => {
// await page.goto('/videos/video_rejected')
//
// // 验证显示驳回状态
// await expect(page.getByText('已驳回')).toBeVisible()
//
// // 验证显示申诉按钮
// await expect(page.getByRole('button', { name: '申诉' })).toBeVisible()
//
// // 点击申诉
// await page.getByRole('button', { name: '申诉' }).click()
//
// // 验证申诉表单
// await expect(page.getByTestId('appeal-form')).toBeVisible()
})
test.skip('should select violations to appeal', async ({ page }) => {
// await page.goto('/videos/video_rejected')
// await page.getByRole('button', { name: '申诉' }).click()
//
// // 显示违规列表
// const violationList = page.getByTestId('appeal-violation-list')
// await expect(violationList).toBeVisible()
//
// // 选择要申诉的违规项
// await violationList.getByRole('checkbox').first().click()
//
// // 验证已选择
// await expect(page.getByText('已选择 1 项')).toBeVisible()
})
test.skip('should require appeal reason >= 10 characters', async ({ page }) => {
// await page.goto('/videos/video_rejected')
// await page.getByRole('button', { name: '申诉' }).click()
//
// // 选择违规项
// await page.getByTestId('appeal-violation-list').getByRole('checkbox').first().click()
//
// // 输入过短的理由
// await page.getByPlaceholder('请输入申诉理由').fill('太短了')
//
// // 尝试提交
// await page.getByRole('button', { name: '提交申诉' }).click()
//
// // 验证错误提示
// await expect(page.getByText('申诉理由至少 10 个字')).toBeVisible()
})
test.skip('should submit appeal successfully', async ({ page }) => {
// await page.goto('/videos/video_rejected')
// await page.getByRole('button', { name: '申诉' }).click()
//
// // 选择违规项
// await page.getByTestId('appeal-violation-list').getByRole('checkbox').first().click()
//
// // 输入申诉理由
// await page.getByPlaceholder('请输入申诉理由').fill('这个词语在此语境下是正常使用,表达的是个人主观感受,不应被判定为违规广告语')
//
// // 提交申诉
// await page.getByRole('button', { name: '提交申诉' }).click()
//
// // 验证成功
// await expect(page.getByText('申诉已提交')).toBeVisible()
// await expect(page.getByText('申诉中')).toBeVisible()
})
test.skip('should deduct appeal token on submit', async ({ page }) => {
// // 获取当前令牌数
// await page.goto('/dashboard')
// const initialTokens = await page.getByTestId('appeal-tokens').textContent()
//
// // 提交申诉
// await page.goto('/videos/video_rejected')
// await page.getByRole('button', { name: '申诉' }).click()
// await page.getByTestId('appeal-violation-list').getByRole('checkbox').first().click()
// await page.getByPlaceholder('请输入申诉理由').fill('这个词语在此语境下是正常使用,不应被判定为违规')
// await page.getByRole('button', { name: '提交申诉' }).click()
//
// // 验证令牌已扣除
// await page.goto('/dashboard')
// const newTokens = await page.getByTestId('appeal-tokens').textContent()
// expect(parseInt(newTokens!)).toBe(parseInt(initialTokens!) - 1)
})
test.skip('should show error when no tokens available', async ({ page }) => {
// // 假设用户无令牌
// await page.goto('/videos/video_rejected')
//
// // 点击申诉按钮
// await page.getByRole('button', { name: '申诉' }).click()
//
// // 验证提示无令牌
// await expect(page.getByText('申诉次数已用完')).toBeVisible()
// await expect(page.getByText('联系管理员')).toBeVisible()
})
})
test.describe('Reviewer Process Appeal', () => {
test.beforeEach(async ({ page }) => {
// 以 Agency 审核员身份登录
// await page.goto('/login')
// await page.getByPlaceholder('邮箱').fill('agency@example.com')
// await page.getByPlaceholder('密码').fill('password123')
// await page.getByRole('button', { name: '登录' }).click()
// await page.waitForURL('/dashboard')
})
test.skip('should display appeal list', async ({ page }) => {
// await page.goto('/appeals')
//
// await expect(page.getByRole('heading', { name: '申诉处理' })).toBeVisible()
// await expect(page.getByTestId('appeal-list')).toBeVisible()
})
test.skip('should show appeal details', async ({ page }) => {
// await page.goto('/appeals/appeal_001')
//
// // 验证显示申诉信息
// await expect(page.getByTestId('appeal-reason')).toBeVisible()
// await expect(page.getByTestId('original-violation')).toBeVisible()
// await expect(page.getByTestId('video-preview')).toBeVisible()
})
test.skip('should approve appeal', async ({ page }) => {
// await page.goto('/appeals/appeal_001')
//
// // 点击通过申诉
// await page.getByRole('button', { name: '申诉成立' }).click()
//
// // 填写处理意见
// await page.getByPlaceholder('处理意见').fill('申诉理由成立')
//
// // 确认
// await page.getByRole('button', { name: '确认' }).click()
//
// // 验证成功
// await expect(page.getByText('申诉已处理')).toBeVisible()
})
test.skip('should reject appeal', async ({ page }) => {
// await page.goto('/appeals/appeal_001')
//
// // 点击驳回申诉
// await page.getByRole('button', { name: '申诉不成立' }).click()
//
// // 填写处理意见
// await page.getByPlaceholder('处理意见').fill('违规判定正确')
//
// // 确认
// await page.getByRole('button', { name: '确认' }).click()
//
// // 验证成功
// await expect(page.getByText('申诉已处理')).toBeVisible()
})
test.skip('should restore token on appeal approval', async ({ page }) => {
// // 审批通过申诉后,达人的令牌应该返还
// // 这个测试需要跨用户验证,可能需要特殊处理
})
})
test.describe('Appeal Status Tracking', () => {
test.skip('should show appeal status in video list', async ({ page }) => {
// await page.goto('/videos')
//
// // 找到正在申诉的视频
// const appealingVideo = page.getByTestId('video-item').filter({ hasText: '申诉中' })
// await expect(appealingVideo).toBeVisible()
//
// // 验证显示申诉状态徽章
// await expect(appealingVideo.getByTestId('appeal-badge')).toBeVisible()
})
test.skip('should notify on appeal result', async ({ page }) => {
// await page.goto('/dashboard')
//
// // 验证通知中心显示申诉结果
// await page.getByRole('button', { name: '通知' }).click()
//
// await expect(page.getByText('申诉结果')).toBeVisible()
})
})