
write-tests
by getsentry
For teams curious about token consumption of their coding agents.
SKILL.md
name: write-tests description: Write tests following project conventions. Use when adding new tests or modifying existing ones. allowed-tools: Read, Grep, Glob, Edit, Write, Bash
Write Tests Skill
Write tests using Vitest. Tests are colocated next to source files.
Structure
src/lib/utils.ts
src/lib/utils.test.ts # colocated
src/app/api/stats/route.ts
src/app/api/stats/route.test.ts
src/test-utils/
├── setup.ts # global setup (PGlite, MSW, auth mock)
├── msw-handlers.ts # external API mocks
└── auth.ts # auth test helpers
Auth Testing
Auth is globally mocked. Use helpers to control auth state:
import { mockAuthenticated, mockUnauthenticated } from '@/test-utils/auth';
it('returns 401 when unauthenticated', async () => {
await mockUnauthenticated();
const response = await GET(new Request('http://localhost/api/foo'));
expect(response.status).toBe(401);
});
it('returns data when authenticated', async () => {
await mockAuthenticated(); // uses default test user
// or with overrides:
await mockAuthenticated({ email: 'custom@example.com' });
const response = await GET(new Request('http://localhost/api/foo'));
expect(response.status).toBe(200);
});
Default test user: test@example.com / Test User
Database Testing
Uses PGlite (in-memory PostgreSQL). No Docker required.
- Schema pushed automatically on boot
- Each test runs in a transaction that rolls back
- Use
insertUsageRecordfrom@/lib/queriesto seed data
import { insertUsageRecord, getOverallStats } from '@/lib/queries';
beforeEach(async () => {
await insertUsageRecord({
date: '2025-01-01',
email: 'user@example.com',
tool: 'claude_code',
model: 'sonnet-4',
rawModel: 'claude-sonnet-4-20250514',
inputTokens: 1000,
outputTokens: 500,
cacheWriteTokens: 0,
cacheReadTokens: 0,
cost: 0.01,
});
});
Running Tests
pnpm test # run all
pnpm test:watch # watch mode
Key Rules
- Colocate tests next to source (
foo.ts→foo.test.ts) - Use
mockAuthenticated()/mockUnauthenticated()for auth - Use
insertUsageRecordfor seeding database - External APIs mocked via MSW in
src/test-utils/msw-handlers.ts
CRITICAL: Auth Tests Required
Every protected route MUST have an auth test. This is non-negotiable.
Session-Authenticated Routes
Routes using getSession() must verify 401 on unauthenticated requests:
it('returns 401 for unauthenticated requests', async () => {
await mockUnauthenticated();
const response = await GET(new Request('http://localhost/api/your-route'));
expect(response.status).toBe(401);
});
Cron Routes
Routes using CRON_SECRET must verify auth:
beforeEach(() => {
vi.stubEnv('CRON_SECRET', 'test-secret');
});
it('returns 401 without authorization header', async () => {
const response = await GET(new Request('http://localhost/api/cron/your-route'));
expect(response.status).toBe(401);
});
it('returns 401 with invalid authorization', async () => {
const response = await GET(
new Request('http://localhost/api/cron/your-route', {
headers: { Authorization: 'Bearer wrong-secret' },
})
);
expect(response.status).toBe(401);
});
Webhook Routes
Routes with signature verification must test invalid signatures:
it('returns 401 without signature', async () => {
const response = await POST(
new Request('http://localhost/api/webhooks/github', {
method: 'POST',
body: '{}',
})
);
expect(response.status).toBe(401);
});
it('returns 401 with invalid signature', async () => {
const response = await POST(
new Request('http://localhost/api/webhooks/github', {
method: 'POST',
body: '{}',
headers: { 'x-hub-signature-256': 'sha256=invalid' },
})
);
expect(response.status).toBe(401);
});
When adding a new route, always ask: "What auth does this route require?" and add the corresponding auth test.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon
