Engineering Advanced APITestingAutomation

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.

You

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?

Agent

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)
  • nullable and example values 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

Best
Claude Opus 4 Claude Sonnet 4 GPT-4.1 Gemini 2.5 Pro Grok 3 Kimi K2
Good
Claude Haiku 4.5 GPT-4.1 mini Gemini 2.5 Flash Grok 3 mini

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.

8K Skill only
32K+ Skill + conversation
100K+ Skill + references + codebase

All current frontier models (Claude, GPT, Gemini) support 100K+ context. Use the full window for complex multi-service work.

Pro tips for best results

1

Be specific

Include numbers — users, budget, RPS — so the skill can size the architecture.

2

Share constraints

Compliance needs, team size, and existing stack all improve the output.

3

Iterate

Start with a high-level design, then ask follow-ups for IaC, cost analysis, or security review.

4

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
← Browse all 169 skills