test-review
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTest Review
测试审查
Review tests for a feature to catch coverage gaps and quality issues before PR.
在PR提交前,针对某个功能的测试进行审查,以发现覆盖缺口和质量问题。
Instructions
操作步骤
- Identify the feature being tested (from user or recent git changes)
- Find related source files: validations, tRPC routers, components, pages
- Find related test files: vitest and playwright
- Check coverage gaps - what's missing?
- Check test quality - are assertions meaningful?
- Check for common mistakes
- Report findings with file:line references
- 确定要测试的功能(从用户需求或近期git变更中获取)
- 找到相关源文件:验证逻辑、tRPC路由、组件、页面
- 找到相关测试文件:vitest和playwright测试文件
- 检查覆盖缺口——哪些内容缺失?
- 检查测试质量——断言是否有意义?
- 检查常见错误
- 附带文件:行号引用报告审查结果
Coverage Gaps
覆盖缺口
Validation Schemas
验证Schema
- Happy path with valid input
- Each required field missing
- Invalid formats (email, date, etc.)
- Edge cases (empty string, zero, negative numbers)
- Type coercion if applicable
- 有效输入的正常流程
- 每个必填字段缺失的情况
- 无效格式(邮箱、日期等)
- 边缘情况(空字符串、零、负数)
- 适用时的类型转换
tRPC Procedures
tRPC 流程
- Success case returns expected shape
- Error case (not found, unauthorized)
- Input validation rejects bad data
- Side effects happen (database updated, email sent)
- 成功案例返回预期结构
- 错误案例(未找到、未授权)
- 输入验证拒绝无效数据
- 副作用触发(数据库更新、邮件发送)
React Components
React 组件
- Renders without crashing
- Displays data correctly
- Loading state
- Error state
- User interactions (click, submit, type)
- Accessibility (keyboard nav, screen reader)
- 渲染时无崩溃
- 数据展示正确
- 加载状态
- 错误状态
- 用户交互(点击、提交、输入)
- 可访问性(键盘导航、屏幕阅读器)
E2E (Playwright)
E2E(Playwright)
- Happy path flow start to finish
- Form validation errors shown to user
- Error recovery (retry, go back)
- Empty states
- 从开始到结束的正常流程
- 表单验证错误向用户展示
- 错误恢复(重试、返回)
- 空状态
Test Quality
测试质量
Meaningful Assertions
有意义的断言
typescript
// Bad - just checks truthy
expect(result).toBeTruthy()
// Good - checks specific value
expect(result.id).toBe('123')
expect(result.items).toHaveLength(3)typescript
// 不佳 - 仅检查真值
expect(result).toBeTruthy()
// 良好 - 检查具体值
expect(result.id).toBe('123')
expect(result.items).toHaveLength(3)Independent Tests
独立测试
- No shared mutable state between tests
- Each test sets up its own data
- Order of tests doesn't matter
- 测试之间无共享可变状态
- 每个测试自行设置数据
- 测试执行顺序不影响结果
Realistic Mocks
真实的Mock
typescript
// Bad - mock returns nothing useful
const mockFetch = jest.fn()
// Good - mock returns realistic data
const mockFetch = jest.fn().mockResolvedValue({
id: '123',
name: 'Test User',
createdAt: new Date(),
})typescript
// 不佳 - Mock未返回有效内容
const mockFetch = jest.fn()
// 良好 - Mock返回真实数据
const mockFetch = jest.fn().mockResolvedValue({
id: '123',
name: 'Test User',
createdAt: new Date(),
})Error Testing
错误测试
typescript
// Bad - just checks it throws
expect(() => fn()).toThrow()
// Good - checks specific error
expect(() => fn()).toThrow('User not found')
expect(() => fn()).toThrow(NotFoundError)typescript
// 不佳 - 仅检查是否抛出错误
expect(() => fn()).toThrow()
// 良好 - 检查具体错误
expect(() => fn()).toThrow('User not found')
expect(() => fn()).toThrow(NotFoundError)Common Mistakes
常见错误
General
通用错误
- No or
.onlyleft in code.skip - No in tests
console.log - No hardcoded IDs that won't exist in CI
- No time-dependent tests without mocking
Date.now()
- 代码中残留或
.only.skip - 测试中存在
console.log - 存在CI环境中不存在的硬编码ID
- 未模拟的时间相关测试
Date.now()
Async Issues
异步问题
typescript
// Bad - no await, test passes before async completes
it('creates user', () => {
createUser({ name: 'Test' })
expect(db.users).toHaveLength(1)
})
// Good - awaits async operation
it('creates user', async () => {
await createUser({ name: 'Test' })
expect(db.users).toHaveLength(1)
})typescript
// 不佳 - 未使用await,测试在异步操作完成前就通过了
it('creates user', () => {
createUser({ name: 'Test' })
expect(db.users).toHaveLength(1)
})
// 良好 - 等待异步操作完成
it('creates user', async () => {
await createUser({ name: 'Test' })
expect(db.users).toHaveLength(1)
})Playwright-Specific
Playwright 专属问题
- Uses semantic locators (,
getByRole) not CSS selectorsgetByLabel - No - use
page.waitForTimeout(),waitForResponse, orwaitForSelectorexpect().toBeVisible() - Tests don't depend on previous test's state
- Assertions check visible outcomes, not implementation
typescript
// Bad - fragile selector, arbitrary timeout
await page.click('.btn-submit')
await page.waitForTimeout(1000)
// Good - semantic locator, waits for outcome
await page.getByRole('button', { name: 'Submit' }).click()
await expect(page.getByText('Saved successfully')).toBeVisible()- 使用语义化定位器(、
getByRole)而非CSS选择器getByLabel - 不使用——改用
page.waitForTimeout()、waitForResponse或waitForSelectorexpect().toBeVisible() - 测试不依赖前序测试的状态
- 断言检查可见结果,而非实现细节
typescript
// 不佳 - 脆弱的选择器,任意超时
await page.click('.btn-submit')
await page.waitForTimeout(1000)
// 良好 - 语义化定位器,等待结果出现
await page.getByRole('button', { name: 'Submit' }).click()
await expect(page.getByText('Saved successfully')).toBeVisible()Vitest-Specific
Vitest 专属问题
- Mocks are reset between tests (in
vi.clearAllMocks())beforeEach - No network calls without MSW or manual mocking
- blocks group related tests logically
describe
- Mock在测试间重置(在中使用
beforeEach)vi.clearAllMocks() - 无MSW或手动Mock的情况下不发起网络请求
- 块按逻辑分组相关测试
describe
Output Format
输出格式
undefinedundefinedTest Review: [feature]
测试审查: [功能名称]
Coverage Gaps
覆盖缺口
- validations/booking.ts has no tests for
updateBookingSchema - No E2E test for delete flow
- Missing error state test for BookingForm component
- validations/booking.ts 缺少的测试
updateBookingSchema - 缺少删除流程的E2E测试
- BookingForm组件缺少错误状态测试
Quality Issues
质量问题
- tests/vitest/booking.test.ts:23 - assertion just checks truthy, verify specific value
- tests/vitest/booking.test.ts:45 - mock returns empty object, use realistic data
- tests/vitest/booking.test.ts:23 - 断言仅检查真值,需验证具体值
- tests/vitest/booking.test.ts:45 - Mock返回空对象,应使用真实数据
Common Mistakes
常见错误
- tests/playwright/booking.spec.ts:12 - uses , use
waitForTimeout(2000)or assertionwaitForResponse - tests/vitest/booking.test.ts:67 - left in code
.only
- tests/playwright/booking.spec.ts:12 - 使用了,应改用
waitForTimeout(2000)或断言waitForResponse - tests/vitest/booking.test.ts:67 - 代码中残留
.only
Passed
通过项
- Validation schema has happy path + required field tests
- tRPC procedures test success and not-found cases
- No hardcoded IDs
- Semantic locators used throughout
undefined- 验证Schema包含正常流程和必填字段测试
- tRPC流程测试了成功和未找到案例
- 无硬编码ID
- 全程使用语义化定位器
undefinedNotes
注意事项
- Focus on changed files first, but check related test files too
- Not every gap needs fixing - use judgment on risk vs effort
- Flag and
.onlyas blockers - these break CI.skip
- 优先关注变更文件,但也要检查相关测试文件
- 并非所有缺口都需要修复——根据风险与投入比做出判断
- 将和
.only标记为阻塞项——这些会破坏CI流程.skip