Skip to main content

write-tests

Write tests following project conventions. Use when adding new tests or modifying existing ones.

معلومات المصدر

المستودع
getsentry/abacus
آخر نشاط في المصدر
١٠ يناير ٢٠٢٦ في ٢٠:٥١
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٧٧
التفرعات
٥

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

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: ```typescript 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 `insertUsageRecord` from `@/lib/queries` to seed data ```typescript 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 ```bash pnpm test # run all pnpm test:watch # watch mode ``` ## Key Rules 1. Colocate tests next to source (`foo.ts` → `foo.test.ts`) 2. Use `mockAuthenticated()`/`mockUnauthenticated()` for auth 3. Use `insertUsageRecord` for seeding database 4. 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: ```typescript 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: ```typescript 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: ```typescript 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.**
عرض على GitHub