
Api Test Suite Builder
Generate structured API route tests—auth, status codes, and helpers—for Node stacks like Vitest and Supertest.
Overview
api-test-suite-builder is an agent skill for the Ship phase that drafts API integration test files with auth, error, and lifecycle patterns for Vitest and Supertest.
Install
npx skills add https://github.com/alirezarezvani/claude-skills --skill api-test-suite-builderWhat is this skill?
- Reference patterns for Vitest + Supertest against Next.js-style API routes.
- Auth matrix: missing header, malformed JWT, and expired token cases with 401 expectations.
- beforeAll/afterAll setup with test users, JWT helpers, and DB cleanup hooks.
- Organizes describe blocks per route and method for maintainable suites.
- Embeds typed request helpers and shared test server creation patterns.
- Example suite covers auth tests including 401 for missing header, malformed token, and expired JWT
Adoption & trust: 536 installs on skills.sh; 17.5k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You shipped API routes but lack consistent automated tests for auth failures, edge tokens, and cleanup between runs.
Who is it for?
Solo devs on Node or Next.js APIs who want agent-generated Supertest coverage before merge or deploy.
Skip if: Greenfield projects with no HTTP server yet, pure frontend component tests, or load/chaos testing at scale.
When should I use this skill?
API routes exist and you need structured integration tests with auth edge cases and test DB lifecycle helpers.
What do I get? / Deliverables
You get runnable describe/it suites with helpers for JWT, users, and DB teardown ready to drop into CI.
- Route-level test files
- Auth negative-case coverage
- Setup/teardown patterns for test data
Recommended Skills
Journey fit
How it compares
Skill-delivered test templates, not a hosted API mocking SaaS or Playwright browser E2E pack.
Common Questions / FAQ
Who is api-test-suite-builder for?
Indie and solo builders maintaining REST or route-handler APIs who want agent help writing Vitest-style integration tests.
When should I use api-test-suite-builder?
In Ship/testing when routes are implemented and you need 401 paths, valid auth flows, and cleanup hooks before release.
Is api-test-suite-builder safe to install?
Check the Security Audits panel on this page; generated tests may touch real DB helpers—review secrets and test isolation in your repo.
SKILL.md
READMESKILL.md - Api Test Suite Builder
# api-test-suite-builder reference ## Example Test Files ### Example 1 — Node.js: Vitest + Supertest (Next.js API Route) ```typescript // tests/api/users.test.ts import { describe, it, expect, beforeAll, afterAll } from 'vitest' import request from 'supertest' import { createServer } from '@/test/helpers/server' import { generateJWT, generateExpiredJWT } from '@/test/helpers/auth' import { createTestUser, cleanupTestUsers } from '@/test/helpers/db' const app = createServer() describe('GET /api/users/:id', () => { let validToken: string let adminToken: string let testUserId: string beforeAll(async () => { const user = await createTestUser({ role: 'user' }) const admin = await createTestUser({ role: 'admin' }) testUserId = user.id validToken = generateJWT(user) adminToken = generateJWT(admin) }) afterAll(async () => { await cleanupTestUsers() }) // --- Auth tests --- it('returns 401 with no auth header', async () => { const res = await request(app).get(`/api/users/${testUserId}`) expect(res.status).toBe(401) expect(res.body).toHaveProperty('error') }) it('returns 401 with malformed token', async () => { const res = await request(app) .get(`/api/users/${testUserId}`) .set('Authorization', 'Bearer not-a-real-jwt') expect(res.status).toBe(401) }) it('returns 401 with expired token', async () => { const expiredToken = generateExpiredJWT({ id: testUserId }) const res = await request(app) .get(`/api/users/${testUserId}`) .set('Authorization', `Bearer ${expiredToken}`) expect(res.status).toBe(401) expect(res.body.error).toMatch(/expired/i) }) it('returns 403 when accessing another user\'s profile without admin', async () => { const otherUser = await createTestUser({ role: 'user' }) const otherToken = generateJWT(otherUser) const res = await request(app) .get(`/api/users/${testUserId}`) .set('Authorization', `Bearer ${otherToken}`) expect(res.status).toBe(403) await cleanupTestUsers([otherUser.id]) }) it('returns 200 with valid token for own profile', async () => { const res = await request(app) .get(`/api/users/${testUserId}`) .set('Authorization', `Bearer ${validToken}`) expect(res.status).toBe(200) expect(res.body).toMatchObject({ id: testUserId }) expect(res.body).not.toHaveProperty('password') expect(res.body).not.toHaveProperty('hashedPassword') }) it('returns 404 for non-existent user', async () => { const res = await request(app) .get('/api/users/00000000-0000-0000-0000-000000000000') .set('Authorization', `Bearer ${adminToken}`) expect(res.status).toBe(404) }) // --- Input validation --- it('returns 400 for invalid UUID format', async () => { const res = await request(app) .get('/api/users/not-a-uuid') .set('Authorization', `Bearer ${adminToken}`) expect(res.status).toBe(400) }) }) describe('POST /api/users', () => { let adminToken: string beforeAll(async () => { const admin = await createTestUser({ role: 'admin' }) adminToken = generateJWT(admin) }) afterAll(cleanupTestUsers) // --- Input validation --- it('returns 422 when body is empty', async () => { const res = await request(app) .post('/api/users') .set('Authorization', `Bearer ${adminToken}`) .send({}) expect(res.status).toBe(422) expect(res.body.errors).toBeDefined() }) it('returns 422 when email is missing', async () => { const res = await request(app) .post('/api/users') .set('Authorization', `Bearer ${adminToken}`) .send({ name: "test-user", role: 'user' }) expect(res.status).toBe(422) expect(res.body.errors).toContainEqual( expect.objectContaining({ field: 'email' }) ) }) it('returns 422 for invalid email format', async () => { const res = await request(app) .post('/api/users') .set('Authorization', `Bear