api-testing

HTTP API testing for TypeScript (Supertest) and Python (httpx, pytest). Test REST APIs, GraphQL, request/response validation, authentication, and error…

INSTALLATION
npx skills add https://github.com/secondsky/claude-skills --skill api-testing
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

API Testing

Expert knowledge for testing HTTP APIs with Supertest (TypeScript/JavaScript) and httpx/pytest (Python).

TypeScript/JavaScript (Supertest)

Installation

# Using Bun

bun add -d supertest @types/supertest

# or: npm install -D supertest @types/supertest

Basic Setup

import { describe, it, expect } from 'vitest'

import request from 'supertest'

import { app } from './app'

describe('API Tests', () => {

  it('returns health status', async () => {

    const response = await request(app)

      .get('/api/health')

      .expect(200)

    expect(response.body).toEqual({ status: 'ok' })

  })

  it('creates a user', async () => {

    const response = await request(app)

      .post('/api/users')

      .send({ name: 'John Doe', email: 'john@example.com' })

      .expect(201)

    expect(response.body).toMatchObject({

      id: expect.any(Number),

      name: 'John Doe',

    })

  })

  it('validates required fields', async () => {

    await request(app)

      .post('/api/users')

      .send({ name: 'John Doe' })

      .expect(400)

  })

})

Request Methods

// GET

await request(app).get('/api/users').expect(200)

// POST with body

await request(app)

  .post('/api/users')

  .send({ name: 'John' })

  .expect(201)

// PUT

await request(app)

  .put('/api/users/1')

  .send({ name: 'Jane' })

  .expect(200)

// DELETE

await request(app).delete('/api/users/1').expect(204)

Headers and Query Parameters

// Set headers

await request(app)

  .get('/api/protected')

  .set('Authorization', 'Bearer token123')

  .expect(200)

// Query parameters

await request(app)

  .get('/api/users')

  .query({ page: 1, limit: 10 })

  .expect(200)

Authentication Testing

describe('Authentication', () => {

  let authToken: string

  beforeAll(async () => {

    const response = await request(app)

      .post('/api/auth/login')

      .send({ email: 'user@example.com', password: 'password123' })

      .expect(200)

    authToken = response.body.token

  })

  it('accesses protected endpoint', async () => {

    await request(app)

      .get('/api/protected')

      .set('Authorization', `Bearer ${authToken}`)

      .expect(200)

  })

  it('rejects without token', async () => {

    await request(app).get('/api/protected').expect(401)

  })

})

Error Handling

it('handles validation errors', async () => {

  const response = await request(app)

    .post('/api/users')

    .send({ email: 'invalid-email' })

    .expect(400)

  expect(response.body).toMatchObject({

    error: 'Validation failed',

    details: expect.any(Array),

  })

})

it('handles not found', async () => {

  await request(app).get('/api/users/999999').expect(404)

})

Python (httpx + pytest)

Installation

uv add --dev httpx pytest-asyncio

Basic Setup

import pytest

from fastapi.testclient import TestClient

from main import app

client = TestClient(app)

def test_health_check():

    response = client.get("/api/health")

    assert response.status_code == 200

    assert response.json() == {"status": "ok"}

def test_create_user():

    response = client.post(

        "/api/users",

        json={"name": "John Doe", "email": "john@example.com"}

    )

    assert response.status_code == 201

    data = response.json()

    assert data["name"] == "John Doe"

    assert "id" in data

def test_not_found():

    response = client.get("/api/users/999")

    assert response.status_code == 404

Fixtures

@pytest.fixture

def auth_token(client):

    response = client.post(

        "/api/auth/login",

        json={"email": "user@example.com", "password": "password123"}

    )

    return response.json()["token"]

def test_protected_endpoint(client, auth_token):

    response = client.get(

        "/api/protected",

        headers={"Authorization": f"Bearer {auth_token}"}

    )

    assert response.status_code == 200

File Upload

def test_file_upload(client, tmp_path):

    test_file = tmp_path / "test.txt"

    test_file.write_text("test content")

    with open(test_file, "rb") as f:

        response = client.post(

            "/api/upload",

            files={"file": ("test.txt", f, "text/plain")}

        )

    assert response.status_code == 200

GraphQL Testing

it('queries GraphQL endpoint', async () => {

  const query = `

    query GetUser($id: ID!) {

      user(id: $id) { id name email }

    }

  `

  const response = await request(app)

    .post('/graphql')

    .send({ query, variables: { id: '1' } })

    .expect(200)

  expect(response.body.data.user).toMatchObject({

    id: '1',

    name: expect.any(String),

  })

})

Performance Testing

it('responds within acceptable time', async () => {

  const start = Date.now()

  await request(app).get('/api/users').expect(200)

  const duration = Date.now() - start

  expect(duration).toBeLessThan(100) // 100ms threshold

})

Best Practices

  • Group related endpoints in describe blocks
  • Reset database between tests
  • Validate status codes first
  • Check response structure
  • Test error message format
  • Mock external services
  • Test both happy path and error cases

See Also

  • vitest-testing - Unit testing framework
  • playwright-testing - E2E API testing
  • test-quality-analysis - Test quality patterns
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card