Ai-setup caliber-testing
Writes Vitest tests following project patterns: __tests__/ dirs, vi.mock() for modules, global LLM mock from src/test/setup.ts, env var save/restore, and describe/it blocks. Use when user says 'write tests', 'add tests', 'test this', or creates *.test.ts files. Do NOT use for non-test code or documentation.
install
source · Clone the upstream repo
git clone https://github.com/caliber-ai-org/ai-setup
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/caliber-ai-org/ai-setup "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.cursor/skills/caliber-testing" ~/.claude/skills/caliber-ai-org-ai-setup-caliber-testing-24f689 && rm -rf "$T"
manifest:
.cursor/skills/caliber-testing/SKILL.mdsource content
Caliber Testing
Critical
- Test location: All tests live in
directories at the same level as the code being tested. File names:__tests__/
.<module>.test.ts - Global LLM mock:
automatically mockssrc/test/setup.ts
,@anthropic-ai/sdk
, and@anthropic-ai/vertex-sdk
. Do NOT re-mock these in individual tests—use the global mock.openai - Env var isolation: Save and restore
inprocess.env
/beforeEach
. See example below.afterEach - Module mocks: Use
at the top of test files withvi.mock()
or define default behavior. Always import the real module and use{ spy: true }
to assert on calls.vi.getMocked()
Instructions
-
Create test file in
__tests__/- Path:
src/<feature>/__tests__/<module>.test.ts - Verify the directory exists; create if needed.
- Path:
-
Import testing utilities and the module under test
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { functionToTest } from '../index.js';- Note: Use
import extensions (ESM convention in this project)..js
- Note: Use
-
Save/restore env vars if your code reads
process.envlet originalEnv: NodeJS.ProcessEnv; beforeEach(() => { originalEnv = { ...process.env }; }); afterEach(() => { process.env = originalEnv; });- Verify this pattern is in place before running tests.
-
Mock external modules using
at file top (if needed)vi.mock()vi.mock('../dependency.js', () => ({ dependencyFunc: vi.fn().mockResolvedValue({ data: 'test' }), }));- Do NOT mock LLM libraries (
,@anthropic-ai/sdk
,openai
)—the global setup handles them.@anthropic-ai/vertex-sdk - Use
to spy on the original implementation if needed.{ spy: true }
- Do NOT mock LLM libraries (
-
Write test cases using
anddescribeitdescribe('functionToTest', () => { it('should return expected value when input is valid', () => { const result = functionToTest('input'); expect(result).toBe('expected'); }); it('should throw error when input is invalid', () => { expect(() => functionToTest(null)).toThrow('Invalid input'); }); });- Verify test names are descriptive and follow "should..." convention.
-
For async code, use
in test functionsasync/awaitit('should fetch data', async () => { const result = await fetchData(); expect(result).toBeDefined(); });- Verify the test waits for all promises to resolve before assertions.
-
Run tests and verify all pass
npm run test -- src/<feature>/__tests__/<module>.test.ts- Or for the whole feature:
npm run test -- src/<feature>/ - Verify exit code is 0 and all assertions pass.
- Or for the whole feature:
Examples
User says: "Write tests for the
detectLanguage function in src/fingerprint/code-analysis.ts."
Actions:
- Create
.src/fingerprint/__tests__/code-analysis.test.ts - Import
and Vitest utilities.detectLanguage - Mock file I/O if needed:
(not LLM).vi.mock('fs/promises') - Write test cases:
import { describe, it, expect, vi } from 'vitest'; import { detectLanguage } from '../code-analysis.js'; vi.mock('fs/promises', () => ({ readFile: vi.fn(), })); describe('detectLanguage', () => { it('should detect TypeScript from file extension', () => { const lang = detectLanguage('foo.ts'); expect(lang).toBe('typescript'); }); it('should detect Python from file extension', () => { const lang = detectLanguage('bar.py'); expect(lang).toBe('python'); }); it('should return unknown for unrecognized extension', () => { const lang = detectLanguage('data.xyz'); expect(lang).toBe('unknown'); }); }); - Run:
npm run test -- src/fingerprint/__tests__/code-analysis.test.ts
Result: Tests pass, file is committed, patterns replicated in future tests.
Common Issues
- "Cannot find module @anthropic-ai/sdk": This means
was not loaded. Verifysrc/test/setup.ts
hasvitest.config.ts
in the config. Check the vitest.config.ts file for correct setup.setupFiles: ['./src/test/setup.ts'] - "ReferenceError: vi is not defined": Add
at the top of the test file.import { vi } from 'vitest' - "Module not found: src/llm/anthropic.js": Check the import path uses
extension (ESM convention). Verify file exists at.js
→ import assrc/llm/anthropic.ts
../anthropic.js - "Timeout: async test did not finish": Add
to test function and ensure all promises are awaited. Example:async/awaitit('test', async () => { await fn(); expect(...); }); - "process.env is dirty after test": Verify
are saving and restoringbeforeEach/afterEach
. Add:process.envbeforeEach(() => { originalEnv = { ...process.env }; }); afterEach(() => { process.env = originalEnv; }); - "Mock is not being called": Use
to assert on mocked function calls. Example:vi.getMocked(module).functionName
.expect(vi.getMocked(fs).readFile).toHaveBeenCalledWith('path')