api-test-suite
Skill1 starsChanged 3 months agoMITView on GitHub
Use when a new or existing API needs test coverage before a release or merge, when onboarding to an unfamiliar API codebase and wanting a safety net first, or when an OpenAPI spec/Postman collection exists and should be turned into a runnable pytest/vitest suite with contract and integration tests.
- Installs packages
In this repository58 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- ascii-artSkill
- caddy-reverse-proxySkill
- changelog-generatorSkill
- color-palette-generatorSkill
- cron-taskSkill
- csv-toolkitSkill
- discord-bot-buildSkill
- docker-umbrellaSkill
- dotfiles-manageSkill
- email-sendSkill
- env-config-managerSkill
- excalidraw-diagramSkill
- file-organizerSkill
- forgejo-self-hostSkill
- frontend-design-toolkitSkill
- generate-dockerfileSkill
- gif-searchSkill
- git-backupSkill
- github-actions-ciSkill
- hallmark-readmeSkill
- http-api-testerSkill
- invoice-generatorSkill
- json-formatterSkill
- log-analyzerSkill
- markdown-linterSkill
- markdown-to-pdfSkill
- markdown-to-slidesSkill
- mcp-server-buildSkill
- media-id-mappingSkill
- movie-catalogue-siteSkill
- movie-night-calendarSkill
- ntfy-notifierSkill
- ocr-documentsSkill
- ollama-localSkill
- openapi-generatorSkill
- password-generatorSkill
- pdf-extractSkill
- portfolio-upkeepSkill
- qr-code-generatorSkill
- regex-testerSkill
- resume-builderSkill
- rss-monitorSkill
- searxng-self-hostSkill
- skill-publishSkill
- skill-registry-catalogSkill
- skills-portfolio-scaffoldSkill
- snippet-managerSkill
- sqlite-dashboardSkill
- streaming-provider-embedsSkill
- tailscale-deploySkill
- telegram-bot-buildSkill
- tmdb-metadataSkill
- uptime-kuma-self-hostSkill
- watchlist-syncSkill
- webhook-receiverSkill
- youtube-transcriptSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 6 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 27
Do not use it for browser UI flows (use a browser-test skill) or for pure unit tests of non-API logic (those belong in a unit test file, …
- Distinctive: line 40
Not found — 404 for unknown IDs.
- Distinctive: line 67
If schemathesis is too heavy, validate responses against a JSON Schema extracted from the spec:
- Distinctive: line 221
Run contract + integration tests against a service spun up in the pipeline.
- Distinctive: line 253
Mocking the database so tests lie: Use a real test database or per-test transaction rollback.
- Distinctive: line 259
Flaky network timing: Add bounded retries only on connection errors, never on assertion failures.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
api-test-suite
Overview
Generate a runnable API test package from an OpenAPI spec, a Postman collection, or by scanning an existing API codebase. The agent produces real, locally-runnable test files — not a hosted-run stub — covering happy path, error cases, and edge cases, then runs the suite and reports pass/fail.
When to Use
- A new API project needs test coverage before it ships.
- The user says "write tests for these endpoints", "add contract tests", or "test my API".
- Pre-release or pre-merge verification of an HTTP API.
- You have an OpenAPI/Postman artifact and want it turned into executable tests.
- You are onboarding to an API codebase and want a safety net first.
Do not use it for browser UI flows (use a browser-test skill) or for pure unit tests of non-API logic (those belong in a unit test file, not the API suite).
Workflow
- Pick the input. One of:
- An OpenAPI/Swagger spec (
openapi.yaml,swagger.json). - A Postman collection (
collection.json). - An API codebase (FastAPI/Express/Flask/Nest/etc.) — scan route definitions.
- An OpenAPI/Swagger spec (
- Enumerate endpoints with method, path, auth scheme, request shape, and response codes.
- Derive test cases per endpoint:
- Happy path — 2xx, response shape matches spec.
- Auth missing/invalid — 401/403.
- Validation failure — 400, with the documented error shape.
- Not found — 404 for unknown IDs.
- Edge cases — empty body, oversized input, malformed JSON, pagination bounds, rate limiting.
- Choose a runner by stack:
- Node/TS →
vitest+supertest(in-process) oraxios(live server). - Python →
pytest+httpx(live server) orfastapi.testclient(in-process).
- Node/TS →
- Emit the file tree (see Test Runner Setup).
- Run the suite. Report pass/fail per file. If a test fails, decide whether it is a real bug in the API or a wrong expectation in the test — fix the API when the expectation is correct, fix the test when it is not. Never delete or weaken an assertion just to turn it green.
Contract Tests
Contract tests assert that the live API's responses conform to the published schema. They catch drift between spec and implementation.
From an OpenAPI spec — Python with schemathesis (property-based, hits the running server):
# tests/contract/test_contract.py
import schemathesis
schema = schemathesis.from_uri("http://localhost:8000/openapi.json")
@schema.parametrize()
def test_api_contract(case, base_url):
# `case` is generated from the spec; this verifies the server honors it
response = case.call(base_url)
case.validate_response(response)If schemathesis is too heavy, validate responses against a JSON Schema extracted from the spec:
# tests/contract/test_shapes.py
import json
import httpx
from jsonschema import Draft202012Validator
spec = json.load(open("openapi.json"))
# pull the response schema for GET /markets -> 200
schema = spec["paths"]["/markets"]["get"]["responses"]["200"]["content"][
"application/json"
]["schema"]
def test_markets_shape(base_url):
r = httpx.get(f"{base_url}/markets?limit=10")
assert r.status_code == 200
Draft202012Validator(schema).validate(r.json())From an OpenAPI spec — Node with a lightweight assertion:
// tests/contract/markets.spec.ts
import { expect } from 'vitest'
import { client } from '../helpers/http'
it('GET /markets 200 matches spec shape', async () => {
const r = await client.get('/markets?limit=10')
expect(r.status).toBe(200)
expect(Array.isArray(r.data.data)).toBe(true)
expect(r.data).toHaveProperty('total')
})Rule: contract tests must read the schema from the artifact, not hardcode a copy that can silently rot.
Integration Tests
Integration tests exercise real HTTP behavior against a running server (or an in-process app) with auth, test data, and cleanup.
Python — fixtures for auth, data, cleanup (pytest):
# tests/integration/test_orders.py
import pytest, httpx
@pytest.fixture
def auth_headers():
# mint a short-lived test token; never use a real user's credentials
token = mint_test_token(scopes=["orders:write"])
return {"Authorization": f"Bearer {token}"}
@pytest.fixture
def created_order(base_url, auth_headers):
r = httpx.post(f"{base_url}/orders", json={"item": "widget", "qty": 1},
headers=auth_headers)
assert r.status_code == 201
yield r.json()["id"]
# cleanup runs even if the test fails
httpx.delete(f"{base_url}/orders/{r.json()['id']}", headers=auth_headers)
def test_create_order_happy(base_url, auth_headers, created_order):
assert isinstance(created_order, str)
def test_create_order_requires_auth(base_url):
r = httpx.post(f"{base_url}/orders", json={"item": "widget"})
assert r.status_code == 401
def test_create_order_bad_payload(base_url, auth_headers):
r = httpx.post(f"{base_url}/orders", json={}, headers=auth_headers)
assert r.status_code == 400Node — vitest + supertest (in-process, no separate server):
// tests/integration/orders.test.ts
import request from 'supertest'
import { app } from '../../src/app'
import { testToken } from '../helpers/auth'
describe('POST /orders', () => {
it('creates an order with valid auth', async () => {
const r = await request(app)
.post('/orders')
.set('Authorization', `Bearer ${testToken()}`)
.send({ item: 'widget', qty: 1 })
expect(r.status).toBe(201)
})
it('rejects missing auth', async () => {
const r = await request(app).post('/orders').send({ item: 'widget' })
expect(r.status).toBe(401)
})
it('rejects empty body', async () => {
const r = await request(app)
.post('/orders')
.set('Authorization', `Bearer ${testToken()}`)
.send({})
expect(r.status).toBe(400)
})
})Test Runner Setup
Emit this layout so the suite is reproducible:
tests/
conftest.py # pytest fixtures: base_url, auth_headers, data, cleanup
contract/
test_contract.py # schema-conformance checks
test_shapes.py
integration/
test_orders.py # real HTTP happy/error/edge cases
helpers/
http.ts / http.py # shared client, base URL from env
auth.ts / auth.py # test-token minting
openapi.json # spec under test (if available)
pytest.ini / vitest.config.tsPython — pytest.ini:
[pytest]
testpaths = tests
addopts = -q --tb=short
env =
BASE_URL=http://localhost:8000Install: pip install pytest httpx schemathesis
Node — vitest.config.ts:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
include: ['tests/**/*.test.ts', 'tests/**/*.spec.ts'],
},
})Install: npm i -D vitest supertest
CI Integration
Run contract + integration tests against a service spun up in the pipeline. GitHub Actions / Forgejo Actions share the same YAML:
name: api-tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
api:
image: ghcr.io/your-org/your-api:ci
ports: ["8000:8000"]
options: >-
--health-cmd "curl -f http://localhost:8000/health"
--health-interval 10s --health-timeout 5s --health-retries 5
env:
BASE_URL: http://localhost:8000
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install pytest httpx schemathesis
- run: pytest tests/ --junitxml=report.xml
- uses: actions/upload-artifact@v4
if: always()
with: { name: api-test-report, path: report.xml }For Node, swap the setup step for actions/setup-node and the run step for npx vitest run.
Common Pitfalls
- Mocking the database so tests lie. Use a real test database or per-test transaction rollback. A test that mocks storage at the wrong boundary passes while the API is broken.
- Hardcoding the response shape instead of reading the spec. Contract tests must derive expectations from the OpenAPI/Postman artifact, or they drift and become noise.
- Shared mutable state across tests. Each test must create and clean up its own data. Seeds that depend on order will flake in CI.
- Using a real user's token for auth. Mint short-lived test tokens scoped to the test tenant; rotate secrets from env, never commit them.
- Rate limiting breaking CI. Hit the API serially in contract runs, or raise the limit for the test tenant. A 429 is a test-harness problem, not an API bug, until proven otherwise.
- Treating generated tests as a substitute for reading the spec. The suite documents behavior; the agent should still confirm the API's intent with the user for ambiguous endpoints.
- Flaky network timing. Add bounded retries only on connection errors, never on assertion failures.
Verification Checklist
- The suite runs with a single command (
pytest tests/ornpx vitest run) and exits 0, or every failure is a confirmed real API bug - Contract tests read the schema from the OpenAPI/Postman artifact at runtime, not a hardcoded copy
- Every endpoint has at least a happy-path test and one auth/validation-failure test
- Auth uses minted test tokens, never a real user's credentials
- Fixtures that create data also tear it down (no orphaned test records after a run)
- CI YAML (if emitted) targets the correct service image/port and uploads the test report artifact
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

