tzurot-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTesting Procedures
测试流程
Invoke with /tzurot-testing for test-related procedures.
Testing patterns are in - they apply automatically.
.claude/rules/02-code-standards.md调用/tzurot-testing 执行各类测试相关流程。
测试模式定义在文件中 - 会自动生效。
.claude/rules/02-code-standards.mdRunning Tests
运行测试
bash
undefinedbash
undefinedRun all tests
Run all tests
pnpm test
pnpm test
Run specific service
Run specific service
pnpm --filter @tzurot/ai-worker test
pnpm --filter @tzurot/ai-worker test
Run specific file
Run specific file
pnpm test -- MyService.test.ts
pnpm test -- MyService.test.ts
Run with coverage
Run with coverage
pnpm test:coverage
pnpm test:coverage
Run only changed packages
Run only changed packages
pnpm focus:test
undefinedpnpm focus:test
undefinedCoverage Audit Procedure
覆盖率审计流程
bash
undefinedbash
undefinedRun unified audit (CI does this automatically)
Run unified audit (CI does this automatically)
pnpm ops test:audit
pnpm ops test:audit
Filter by category
Filter by category
pnpm ops test:audit --category=services
pnpm ops test:audit --category=contracts
pnpm ops test:audit --category=services
pnpm ops test:audit --category=contracts
Update baseline (after closing gaps)
Update baseline (after closing gaps)
pnpm ops test:audit --update
pnpm ops test:audit --update
Strict mode (fails on ANY gap)
Strict mode (fails on ANY gap)
pnpm ops test:audit --strict
**Unified Baseline**: `test-coverage-baseline.json` (project root)pnpm ops test:audit --strict
**统一基准文件**:`test-coverage-baseline.json`(项目根目录)Test File Types
测试文件类型
| Type | Pattern | Location | Infrastructure |
|---|---|---|---|
| Unit | | Next to source | Fully mocked |
| Integration | | Next to source | PGLite |
| Schema | | | Zod only |
| 类型 | 命名模式 | 存放位置 | 基础设施 |
|---|---|---|---|
| 单元测试 | | 源代码旁 | 完全模拟 |
| 集成测试 | | 源代码旁 | PGLite |
| Schema测试 | | | 仅使用Zod |
Debugging Test Failures
调试测试失败问题
1. Run Specific Test
1. 运行指定测试
bash
pnpm test -- MyService.test.ts --reporter=verbosebash
pnpm test -- MyService.test.ts --reporter=verbose2. Check for Fake Timer Issues
2. 检查虚假计时器问题
typescript
// ❌ WRONG - Promise rejection warning
const promise = asyncFunction();
await vi.runAllTimersAsync(); // Rejection happens here!
await expect(promise).rejects.toThrow(); // Too late
// ✅ CORRECT - Attach handler BEFORE advancing
const promise = asyncFunction();
const assertion = expect(promise).rejects.toThrow('Error');
await vi.runAllTimersAsync();
await assertion;typescript
// ❌ WRONG - Promise rejection warning
const promise = asyncFunction();
await vi.runAllTimersAsync(); // Rejection happens here!
await expect(promise).rejects.toThrow(); // Too late
// ✅ CORRECT - Attach handler BEFORE advancing
const promise = asyncFunction();
const assertion = expect(promise).rejects.toThrow('Error');
await vi.runAllTimersAsync();
await assertion;3. Reset Mock State
3. 重置模拟状态
typescript
beforeEach(() => {
vi.clearAllMocks(); // Clear call history, keep impl
});
afterEach(() => {
vi.restoreAllMocks(); // Restore originals (spies only)
});typescript
beforeEach(() => {
vi.clearAllMocks(); // Clear call history, keep impl
});
afterEach(() => {
vi.restoreAllMocks(); // Restore originals (spies only)
});Creating Mock Factories
创建模拟工厂
typescript
// Use async factory for vi.mock hoisting
vi.mock('./MyService.js', async () => {
const { mockMyService } = await import('../test/mocks/MyService.mock.js');
return mockMyService;
});
// Import accessors after vi.mock
import { getMyServiceMock } from '../test/mocks/index.js';
it('should call service', () => {
expect(getMyServiceMock().someMethod).toHaveBeenCalled();
});typescript
// Use async factory for vi.mock hoisting
vi.mock('./MyService.js', async () => {
const { mockMyService } = await import('../test/mocks/MyService.mock.js');
return mockMyService;
});
// Import accessors after vi.mock
import { getMyServiceMock } from '../test/mocks/index.js';
it('should call service', () => {
expect(getMyServiceMock().someMethod).toHaveBeenCalled();
});Integration Tests with PGLite
基于PGLite的集成测试
typescript
describe('UserService', () => {
let pglite: PGlite;
let prisma: PrismaClient;
beforeAll(async () => {
pglite = new PGlite({ extensions: { vector } });
await pglite.exec(loadPGliteSchema());
prisma = new PrismaClient({ adapter: new PrismaPGlite(pglite) });
});
it('should create user', async () => {
const service = new UserService(prisma);
const userId = await service.getOrCreateUser('123', 'testuser');
expect(userId).toBeDefined();
});
});⚠️ ALWAYS use - NEVER create tables manually!
loadPGliteSchema()typescript
describe('UserService', () => {
let pglite: PGlite;
let prisma: PrismaClient;
beforeAll(async () => {
pglite = new PGlite({ extensions: { vector } });
await pglite.exec(loadPGliteSchema());
prisma = new PrismaClient({ adapter: new PrismaPGlite(pglite) });
});
it('should create user', async () => {
const service = new UserService(prisma);
const userId = await service.getOrCreateUser('123', 'testuser');
expect(userId).toBeDefined();
});
});⚠️ 务必使用 - 禁止手动创建表!
loadPGliteSchema()Integration Test Triggers
集成测试触发条件
Integration tests () run separately from unit tests and are not included in or pre-push hooks.
*.int.test.tspnpm testAlways run after:
pnpm test:int| Change | Why |
|---|---|
| Add/remove slash command options | |
| Add/remove subcommands | Same snapshot tests |
| Restructure command directories | |
| Change component prefix routing | Integration tests verify button/select menu routing |
Update snapshots with:
pnpm vitest run --config vitest.int.config.ts <file> --update集成测试()与单元测试分开运行,不会包含在或预推送钩子中。
*.int.test.tspnpm test在以下变更后务必运行:
pnpm test:int| 变更类型 | 原因 |
|---|---|
| 添加/移除斜杠命令选项 | |
| 添加/移除子命令 | 同样涉及快照测试 |
| 重构命令目录结构 | |
| 修改组件前缀路由 | 集成测试会验证按钮/选择菜单的路由 |
更新快照命令:
pnpm vitest run --config vitest.int.config.ts <file> --updateDefinition of Done
完成标准
- New service files have
.int.test.ts - New API schemas have
.schema.test.ts - Coverage doesn't drop (Codecov enforces 80%)
- Run to verify no new gaps
pnpm ops test:audit
- 新服务文件需包含测试文件
.int.test.ts - 新API Schema需包含测试文件
.schema.test.ts - 覆盖率不得下降(Codecov强制要求80%覆盖率)
- 运行验证无新的覆盖率缺口
pnpm ops test:audit
References
参考资料
- Full testing guide:
docs/reference/guides/TESTING.md - Mock factories:
services/*/src/test/mocks/ - PGLite setup:
docs/reference/testing/PGLITE_SETUP.md - Coverage audit:
docs/reference/testing/COVERAGE_AUDIT_SYSTEM.md - Rules:
.claude/rules/02-code-standards.md
- 完整测试指南:
docs/reference/guides/TESTING.md - 模拟工厂示例:
services/*/src/test/mocks/ - PGLite配置:
docs/reference/testing/PGLITE_SETUP.md - 覆盖率审计系统:
docs/reference/testing/COVERAGE_AUDIT_SYSTEM.md - 编码规范:
.claude/rules/02-code-standards.md