API Test Suite Builder
Scan API routes and generate complete test suites automatically.
$skillfish add ~skills/api-test-suite-builder Real Conversations
See how the API Test Suite Builder skill responds to actual requests. These are representative examples of what your AI agent will produce.
I have an Express.js API with 23 routes. I've been testing manually with Postman. Can you scan the routes and generate a proper Jest + supertest suite?
With an OpenAPI 3.0 spec and 34 endpoints, the approach is to parse the spec systematically and generate tests in three layers: happy paths, error cases, and edge cases. Here's exactly how this works.
Generation Strategy
For each endpoint in your spec, I extract:
- HTTP method and path
- Required vs optional parameters
- Request body schema (required fields, types, constraints like
minLength,maxLength,enum) - Response schemas for each status code
- Security requirements (JWT Bearer, API keys)
nullableandexamplevalues from the spec
From these, I generate test cases covering every meaningful scenario.
Example Output — POST /api/v1/users
// tests/api/users/create.test.ts
import request from 'supertest';
import { app } from '../../../src/app';
import { getAuthToken, clearUsers } from '../../helpers';
describe('POST /api/v1/users', () => {
let adminToken: string;
beforeAll(async () => {
adminToken = await getAuthToken({ role: 'admin' });
});
afterEach(async () => {
await clearUsers();
});
// ── Happy path ──────────────────────────────────────────
it('201 — creates user with valid payload', async () => {
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${adminToken}`)
.send({ email: 'test@example.com', name: 'Test User', role: 'viewer' });
expect(res.status).toBe(201);
expect(res.body).toMatchObject({
id: expect.any(String),
email: 'test@example.com',
name: 'Test User',
role: 'viewer',
});
expect(res.body).not.toHaveProperty('passwordHash'); // PII leak check
expect(res.headers['content-type']).toMatch(/json/);
});
// ── Auth errors ──────────────────────────────────────────
it('401 — rejects request without auth token', async () => {
const res = await request(app)
.post('/api/v1/users')
.send({ email: 'test@example.com', name: 'Test User' });
expect(res.status).toBe(401);
});
it('403 — rejects non-admin creating admin user', async () => {
const viewerToken = await getAuthToken({ role: 'viewer' });
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${viewerToken}`)
.send({ email: 'test@example.com', name: 'Test', role: 'admin' });
expect(res.status).toBe(403);
});
// ── Validation errors ────────────────────────────────────
it('422 — rejects missing required fields', async () => {
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${adminToken}`)
.send({ name: 'Test User' }); // missing email
expect(res.status).toBe(422);
expect(res.body.errors).toEqual(
expect.arrayContaining([
expect.objectContaining({ field: 'email' })
])
);
});
it('422 — rejects invalid email format', async () => {
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${adminToken}`)
.send({ email: 'not-an-email', name: 'Test User' });
expect(res.status).toBe(422);
});
it('409 — rejects duplicate email', async () => {
const payload = { email: 'dup@example.com', name: 'User' };
await request(app).post('/api/v1/users').set('Authorization', `Bearer ${adminToken}`).send(payload);
const res = await request(app).post('/api/v1/users').set('Authorization', `Bearer ${adminToken}`).send(payload);
expect(res.status).toBe(409);
});
// ── Edge cases ───────────────────────────────────────────
it('422 — rejects name exceeding maxLength (255 chars)', async () => {
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${adminToken}`)
.send({ email: 'test@example.com', name: 'a'.repeat(256) });
expect(res.status).toBe(422);
});
it('handles special characters in name field', async () => {
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${adminToken}`)
.send({ email: 'test@example.com', name: "O'Reilly <script>alert(1)</script>" });
expect(res.status).toBe(201);
expect(res.body.name).not.toContain('<script>'); // XSS sanitization check
});
});
Handling Authentication Across 34 Endpoints
Most endpoints will share auth setup. A shared helper pattern keeps tests DRY:
// tests/helpers/auth.ts
import jwt from 'jsonwebtoken';
export async function getAuthToken(opts: { role: string; userId?: string }): Promise<string> {
return jwt.sign(
{ sub: opts.userId ?? 'test-user-id', role: opts.role },
process.env.JWT_SECRET!,
{ expiresIn: '1h' }
);
}
For API key auth (if your spec uses apiKey security scheme):
// tests/helpers/auth.ts (API key variant)
export const TEST_API_KEY = 'test-key-do-not-use-in-production';
// Seed this key in your test database setup
Coverage Summary for a 34-Endpoint Spec
| Endpoint category | Happy path | Auth (401/403) | Validation (422) | Edge cases |
|---|---|---|---|---|
| Resource creation (POST) | 1 test each | 2 tests each | 3–5 tests each | 2–3 tests each |
| Resource reads (GET) | 1 test each | 1–2 tests each | 1 test (404) | 1 test (empty arrays) |
| Updates (PUT/PATCH) | 1 test each | 2 tests each | 3–4 tests each | partial update cases |
| Deletes (DELETE) | 1 test each | 2 tests each | 1 test (404) | idempotency check |
For 34 endpoints, this generates approximately 180–220 test cases covering all documented behavior. The spec's example values seed the happy path; required fields drive the 422 validation tests; security schemes drive the 401/403 tests; maxLength, minLength, pattern, and enum constraints drive the edge cases.
Run the suite with:
npm test -- --testPathPattern=tests/api
# With coverage:
npm test -- --testPathPattern=tests/api --coverage --collectCoverageFrom='src/**/*.ts'
Get Started
How to install and use this skill in your preferred environment.
Skills are designed for AI coding agents (Claude Code, Cursor, Windsurf) and IDE-based workflows where the agent can read files, run scripts, and act on your codebase. Web-based AI can use the knowledge and frameworks, but won't have tool access.
Models & Context
Which AI models and context windows work best with this skill.
Recommended Models
Larger models produce more detailed, production-ready outputs.
Context Window
This skill's SKILL.md is typically 3–10 KB — fits in any modern context window.
All current frontier models (Claude, GPT, Gemini) support 100K+ context. Use the full window for complex multi-service work.
Pro tips for best results
Be specific
Include numbers — users, budget, RPS — so the skill can size the architecture.
Share constraints
Compliance needs, team size, and existing stack all improve the output.
Iterate
Start with a high-level design, then ask follow-ups for IaC, cost analysis, or security review.
Combine skills
Pair with companion skills below for end-to-end coverage.
Ready to try API Test Suite Builder?
Install the skill and start getting expert-level guidance in your workflow — any agent, any IDE.
$skillfish add ~skills/api-test-suite-builder