.claude/skills/tzurot-testing/SKILL.md
Testing procedures. Invoke with /tzurot-testing for test execution, coverage audits, and debugging test failures.
npx skillsauth add lbds137/tzurot tzurot-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Invoke with /tzurot-testing for test-related procedures.
Testing patterns are in .claude/rules/02-code-standards.md - they apply automatically.
# Run all tests
pnpm test
# Run specific service
pnpm --filter @tzurot/ai-worker test
# Run specific file
pnpm test -- MyService.test.ts
# Run with coverage
pnpm test:coverage
# Run only changed packages
pnpm focus:test
# Run unified audit (CI does this automatically)
pnpm ops test:audit
# Filter by category
pnpm ops test:audit --category=services
pnpm ops test:audit --category=contracts
# Update baseline (after closing gaps)
pnpm ops test:audit --update
# Strict mode (fails on ANY gap)
pnpm ops test:audit --strict
Unified Baseline: test-coverage-baseline.json (project root)
| Type | Pattern | Location | Infrastructure |
| ----------- | ------------------ | --------------------- | -------------- |
| Unit | *.test.ts | Next to source | Fully mocked |
| Integration | *.int.test.ts | Next to source | PGLite |
| Schema | *.schema.test.ts | common-types/types/ | Zod only |
pnpm test -- MyService.test.ts --reporter=verbose
// ❌ 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;
beforeEach(() => {
vi.clearAllMocks(); // Clear call history, keep impl
});
afterEach(() => {
vi.restoreAllMocks(); // Restore originals (spies only)
});
// 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();
});
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 loadPGliteSchema() - NEVER create tables manually!
Integration tests (*.int.test.ts) run separately from unit tests and are not included in pnpm test or pre-push hooks.
Always run pnpm test:int after:
| Change | Why |
| -------------------------------- | --------------------------------------------------------------------- |
| Add/remove slash command options | CommandHandler.int.test.ts snapshots capture full command structure |
| Add/remove subcommands | Same snapshot tests |
| Restructure command directories | getCommandFiles() discovery changes affect command loading |
| 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.ts.schema.test.tspnpm ops test:audit to verify no new gapsdocs/reference/guides/TESTING.mdservices/*/src/test/mocks/docs/reference/testing/PGLITE_SETUP.mddocs/reference/testing/COVERAGE_AUDIT_SYSTEM.md.claude/rules/02-code-standards.mdtools
Git workflow procedures. Invoke with /tzurot-git-workflow for commit, PR, and release procedures.
documentation
Session workflow procedures. Invoke with /tzurot-docs for session start/end, CURRENT.md/BACKLOG.md management.
tools
Documentation and auto-memory freshness audit. Invoke with /tzurot-doc-audit to review docs and Claude auto-memory for staleness, items in the wrong layer, and missing-tool drift.
testing
Railway deployment procedures. Invoke with /tzurot-deployment for deploying, checking logs, and troubleshooting.