SuperAPI AI 工具集

vitest-testing-patterns

测试与质量

查看项目

更新于 10-15 14:52

技能介绍

Vitest Testing Patterns 是一个帮助开发者使用 Vitest 和 React Testing Library 编写有效测试的技能,遵循项目约定。

用途

该技能适用于以下场景:为工具函数和函数编写单元测试;使用 React Testing Library 创建组件测试;为 API 调用、数据库或外部服务设置 mock;集成测试模式;理解测试覆盖率与 CI 设置。

不适用于以下场景:Jest 专有模式(两者相似,但需查阅 Jest 文档了解差异);端到端测试(应使用 Playwright 或 Cypress 技能);性能测试(应使用专用性能工具);API 契约测试(应使用 OpenAPI/Pact 模式)。

测试基础设施

  • 配置:vitest.config.ts
  • 环境:jsdom
  • 安装文件:src/test/setup.ts
  • 覆盖率:v8 提供器

命令:

  • npm test:监听模式
  • npm run test:run:单次运行
  • npm run test:coverage:带覆盖率运行

文件组织

测试文件按以下结构组织:

  • src/app/api/tests/:API 路由测试
  • src/components/tests/:组件测试
  • src/lib/tests/:库/工具测试
  • src/lib/{feature}/tests/:特定功能测试

测试文件命名为 {name}.test.ts 或 {name}.test.tsx。

核心测试模式

API 路由测试

从 vitest 导入 describe、it、expect、vi、beforeEach,从路由文件导入 GET、POST,从 next/server 导入 NextRequest。使用 vi.mock 模拟依赖,例如模拟 @/lib/auth 的 getSession,以及模拟 @/db 的数据库查询链。在 beforeEach 中调用 vi.clearAllMocks()。测试未认证时返回 401,认证时返回数据。

组件测试

从 @testing-library/react 导入 render、screen、waitFor,从 @testing-library/user-event 导入 userEvent。使用 vi.mock 模拟 hooks,例如 @/hooks/useAuth。测试加载状态、用户交互和错误状态。使用 userEvent.setup() 创建用户事件实例,通过 screen.getByRole 获取元素并交互。

库/工具测试

从 vitest 导入 describe、it、expect、vi、beforeEach、afterEach。测试数据转换正确性和无效输入抛出错误。使用 vi.useFakeTimers() 和 vi.setSystemTime() 模拟时间,在 afterEach 中调用 vi.useRealTimers() 恢复。

Mock 模式

模块 Mock

使用 vi.mock 模拟整个模块,例如 @/lib/auth。可使用 vi.importActual 进行部分实现模拟,例如 date-fns。可模拟默认导出,例如 @anthropic-ai/sdk。

函数 Mock

使用 vi.fn() 创建 mock 函数。设置返回值:mockReturnValue、mockResolvedValue、mockRejectedValue。一次性行为:mockReturnValueOnce。自定义实现:mockImplementation。验证调用:toHaveBeenCalled、toHaveBeenCalledTimes、toHaveBeenCalledWith。

链式 Mock 模式(Drizzle ORM)

模拟 @/db 的 select、from、where、orderBy、limit 链式调用,以及 insert、values、returning 链式调用。

定时器 Mock

使用 vi.useFakeTimers() 和 vi.advanceTimersByTime() 测试防抖函数。

查询优先级

按以下顺序使用查询(从最推荐到最不推荐):

  1. getByRole:可访问性查询(按钮、链接、标题)
  2. getByLabelText:带标签的表单字段
  3. getByPlaceholderText:带占位符的输入框
  4. getByText:非交互元素
  5. getByTestId:最后手段(data-testid)

异步模式

  • 等待元素出现:await waitFor(() => { expect(screen.getByText('Loaded')).toBeInTheDocument(); })
  • 内置 waitFor:const element = await screen.findByText('Loaded')
  • 等待元素消失:await waitFor(() => { expect(screen.queryByText('Loading')).not.toBeInTheDocument(); })

测试清理

从 @testing-library/react 导入 cleanup。在 afterEach 中调用 cleanup()(setup.ts 中自动执行)、vi.clearAllMocks()、vi.resetAllMocks()、vi.restoreAllMocks()。

可访问性测试

从 jest-axe 导入 axe、toHaveNoViolations。使用 expect.extend(toHaveNoViolations)。测试组件无可访问性违规。

常用匹配器

来自 setup.ts 的 jest-dom 匹配器:toBeInTheDocument、toBeVisible、toBeDisabled、toHaveTextContent、toHaveAttribute、toHaveClass、toHaveValue。

参考

  • Vitest Mocking Guide
  • React Testing Library
  • Testing Library Queries