test-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Test Review

测试审查

Review tests for a feature to catch coverage gaps and quality issues before PR.
在PR提交前,针对某个功能的测试进行审查,以发现覆盖缺口和质量问题。

Instructions

操作步骤

  1. Identify the feature being tested (from user or recent git changes)
  2. Find related source files: validations, tRPC routers, components, pages
  3. Find related test files: vitest and playwright
  4. Check coverage gaps - what's missing?
  5. Check test quality - are assertions meaningful?
  6. Check for common mistakes
  7. Report findings with file:line references
  1. 确定要测试的功能(从用户需求或近期git变更中获取)
  2. 找到相关源文件:验证逻辑、tRPC路由、组件、页面
  3. 找到相关测试文件:vitest和playwright测试文件
  4. 检查覆盖缺口——哪些内容缺失?
  5. 检查测试质量——断言是否有意义?
  6. 检查常见错误
  7. 附带文件:行号引用报告审查结果

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
    .only
    or
    .skip
    left in code
  • No
    console.log
    in tests
  • 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
    ,
    getByLabel
    ) not CSS selectors
  • No
    page.waitForTimeout()
    - use
    waitForResponse
    ,
    waitForSelector
    , or
    expect().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
    getByLabel
    )而非CSS选择器
  • 不使用
    page.waitForTimeout()
    ——改用
    waitForResponse
    waitForSelector
    expect().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 (
    vi.clearAllMocks()
    in
    beforeEach
    )
  • No network calls without MSW or manual mocking
  • describe
    blocks group related tests logically
  • Mock在测试间重置(在
    beforeEach
    中使用
    vi.clearAllMocks()
  • 无MSW或手动Mock的情况下不发起网络请求
  • describe
    块按逻辑分组相关测试

Output Format

输出格式

undefined
undefined

Test 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
    waitForTimeout(2000)
    , use
    waitForResponse
    or assertion
  • tests/vitest/booking.test.ts:67 -
    .only
    left in code
  • 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
  • 全程使用语义化定位器
undefined

Notes

注意事项

  • Focus on changed files first, but check related test files too
  • Not every gap needs fixing - use judgment on risk vs effort
  • Flag
    .only
    and
    .skip
    as blockers - these break CI
  • 优先关注变更文件,但也要检查相关测试文件
  • 并非所有缺口都需要修复——根据风险与投入比做出判断
  • .only
    .skip
    标记为阻塞项——这些会破坏CI流程