write-tests

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Write Tests for Existing Code

为现有代码编写测试

Before Writing, Ask Yourself

编写前,请先自问

  • Module type? Route handler, repository, plugin, utility, or service — each has a different mock strategy
  • Blast radius? Does this module have side effects (DB writes, API calls) that need isolation?
  • Nearest test file? Find the closest
    *.test.ts
    and match its structure exactly
  • 模块类型? 路由处理器、仓库、插件、工具类或服务——每种类型都有不同的Mock策略
  • 影响范围? 该模块是否有需要隔离的副作用(如数据库写入、API调用)?
  • 最近的测试文件? 找到最近的
    *.test.ts
    文件,并完全匹配其结构

Mock Strategy by Module Type

按模块类型划分的Mock策略

Module TypeStrategy
Route handlerTest app builder + session simulation +
app.inject()
RepositoryMock DB connection + counter-based
execute
Framework pluginReal framework instance + selective dependency mocks
Pure utilityNo mocks — test inputs/outputs directly
Service w/ DIMock injected deps via forwarding pattern
模块类型策略
路由处理器测试应用构建器 + 会话模拟 +
app.inject()
仓库Mock数据库连接 + 基于计数器的
execute
方法
框架插件真实框架实例 + 选择性依赖Mock
纯工具类无需Mock——直接测试输入/输出
依赖注入服务通过转发模式Mock注入的依赖项

Mock Setup (mockReset: true)

Mock设置(mockReset: true)

If your test runner uses
mockReset: true
, most examples from the internet will silently fail.
typescript
const { mockFn } = vi.hoisted(() => ({
  mockFn: vi.fn(),
}));

vi.mock("./dependency", () => ({
  dependency: (...args: unknown[]) => mockFn(...args),
}));

beforeEach(() => {
  // MUST reconfigure here — mockReset clears return values between tests
  mockFn.mockResolvedValue(defaultResult);
});
For complex TDZ cases (multiple interdependent mocks), use the globalThis registry pattern.
如果你的测试运行器启用了
mockReset: true
,网上的大多数示例都会静默失败
typescript
const { mockFn } = vi.hoisted(() => ({
  mockFn: vi.fn(),
}));

vi.mock("./dependency", () => ({
  dependency: (...args: unknown[]) => mockFn(...args),
}));

beforeEach(() => {
  // MUST reconfigure here — mockReset clears return values between tests
  mockFn.mockResolvedValue(defaultResult);
});
对于复杂的TDZ(暂时性死区)场景(多个相互依赖的Mock),请使用globalThis注册表模式

NEVER

绝对禁止

  • NEVER chain
    mockResolvedValueOnce
    mockReset
    clears the chain between tests. Use counter-based
    mockImplementation
    instead.
  • NEVER define mock variables at module scope then reference in
    vi.mock()
    factories
    — hoisting creates a temporal dead zone. Use
    vi.hoisted()
    or globalThis.
  • NEVER
    vi.importActual()
    for modules with side effects
    — use selective re-exports.
  • NEVER test implementation details (private state, internal call order) — test behavior through the public API.
  • NEVER copy mock patterns from other projects — check YOUR test runner config first.
  • NEVER modify source code — this skill writes tests only.
  • 绝对不要链式调用
    mockResolvedValueOnce
    ——
    mockReset
    会在测试间清除调用链。请改用基于计数器的
    mockImplementation
  • 绝对不要在模块作用域定义Mock变量,然后在
    vi.mock()
    工厂中引用
    ——变量提升会导致暂时性死区。请使用
    vi.hoisted()
    或globalThis。
  • 绝对不要对有副作用的模块使用
    vi.importActual()
    ——请使用选择性重导出。
  • 绝对不要测试实现细节(私有状态、内部调用顺序)——请通过公开API测试行为。
  • 绝对不要照搬其他项目的Mock模式——请先检查你自己的测试运行器配置。
  • 绝对不要修改源代码——本技能仅负责编写测试。

Metacognitive Rule

元认知规则

If >3 tests fail on first run: STOP. The root cause is almost certainly a mock wiring issue affecting all tests, not individual test logic errors. Re-examine the mock setup strategy holistically before fixing tests one by one.
如果首次运行时有超过3个测试失败:请停止。 根本原因几乎肯定是影响所有测试的Mock配置问题,而非单个测试逻辑错误。在逐个修复测试前,请先全面检查Mock设置策略。

Run

运行测试

bash
npx vitest run <test-file> --reporter=verbose
bash
npx vitest run <test-file> --reporter=verbose

Arguments

参数

  • $ARGUMENTS
    : Path to the source file or module to cover
    • Example:
      /write-tests src/routes/admin/settings.ts
    • If empty, ask the user which file needs test coverage
  • $ARGUMENTS
    : 需要覆盖测试的源文件或模块路径
    • 示例:
      /write-tests src/routes/admin/settings.ts
    • 如果留空,请询问用户需要测试哪个文件