ts-testinglisted
Install: claude install-skill AllThingsSmitty/agent-skills
# TypeScript Testing
Tests that use `as any` to satisfy the type checker aren't testing the types — they're hiding them. The goal is tests that are type-safe at the boundary, test the public interface rather than internals, and give meaningful errors when types change.
## Jest setup for TypeScript
Use `ts-jest` or Vitest's native TypeScript support. Avoid transpile-only setups (like `babel-jest` without type checking) for type-related tests — they skip type errors.
**Vitest** (preferred for new projects):
```ts
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({ test: { globals: true } });
```
**Jest with ts-jest**:
```json
// jest.config.json
{ "preset": "ts-jest", "testEnvironment": "node" }
```
## Type-safe mocks with `jest.fn`
Always provide the type parameter to `jest.fn` — don't let it default to `jest.Mock` (which is effectively `any`).
```ts
// Bad: loses type information
const fetchUser = jest.fn();
// Good: typed mock
const fetchUser = jest.fn<Promise<User>, [string]>();
fetchUser.mockResolvedValue({ id: '1', name: 'Alice' });
```
For mocking module-level functions, use `jest.mocked()` (Jest 27+) or `vi.mocked()` (Vitest) instead of casting:
```ts
import { sendEmail } from './email';
jest.mock('./email');
const mockSendEmail = jest.mocked(sendEmail);
mockSendEmail.mockResolvedValue(undefined);
```
`jest.mocked()` returns the function with its mock type overlaid — no `as any` needed.
## Mocking interfaces and