基于项目需求文档(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>
211 lines
7.8 KiB
TypeScript
211 lines
7.8 KiB
TypeScript
/**
|
||
* 申诉流程 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()
|
||
})
|
||
})
|