API Testing
Test APIs thoroughly - REST endpoint testing with Supertest, contract testing with Pact, authentication scenarios, and error case coverage.
skill: API Testing category: Engineering tags: [API Testing, REST, Supertest, Pact, Contract Testing] readingTime: 4
API tests are the sweet spot of the testing pyramid - faster than E2E, higher-level than unit tests. A comprehensive API test suite verifies that the HTTP interface works correctly without requiring a browser. Test every HTTP status code your API returns, not just 200 OK.
Workflow
- Test REST endpoints with SupertestSupertest sends real HTTP requests to your Express/Fastify/Hono server without starting an actual network listener. Tests run in-process, fast, with access to the test database.
- Test all response codesAPIs return many status codes - 400 for bad input, 401 for auth, 403 for authorization, 404 for not found, 409 for conflict, 422 for validation. Untested paths are unverified behavior.
- Validate OpenAPI schemasSchema validation catches API drift - when the code diverges from the documented contract. Automated schema validation prevents silent breaking changes.
- Write contract tests with PactPact tests verify that provider APIs fulfill the contracts that consumers depend on - catching breaking changes before they reach production in microservices architectures.
- Test authentication and authorizationAuth bugs are security vulnerabilities, not just test failures. Systematically test auth matrix - every role × every endpoint.
Output Format
API testing: Supertest in-process HTTP, test all status codes (201/400/401/403/409/422), AJV schema validation vs OpenAPI, Pact consumer→provider contract, and auth matrix for every role×endpoint.
request(app).get("/api/orders").set("Authorization", bearer).query({ page:0 }).expect(200)
.expect(401) without token; .expect(403) for wrong user; .expect(422) for invalid input
ajv.compile(openApiSchema)(response.body) → schema drift detection
PactV3: consumer defines expectation → provider verifies
Auth matrix: [unauthenticated, user, admin] × [public, authenticated, adminOnly] endpointsExamples
Input
Output
Edge Cases & Gotchas
- Test database isolation - Tests mutating the same database table in parallel fail nondeterministically. Use transactions that rollback after each test, or create uniquely named test resources (email with timestamp).
- Rate limiting in tests - Rate limiting middleware blocks rapid test requests. Disable rate limiting in test environment, or reset the rate limit counter in beforeEach for tests that deliberately probe rate limit behavior.
- Large file upload testing - Supertest supports file uploads: request(app).post("/upload").attach("file", Buffer.from("content"), { filename: "test.pdf", contentType: "application/pdf" }).
- Idempotency key testing - Payment and order APIs with idempotency keys need tests for: first call (creates), second call with same key (returns same response without duplicating), different key (creates new).
When to Break These Rules
- Use Postman/Newman for API testing when the team is non-technical (QA with limited coding experience) - Postman's GUI is more accessible than code-based Supertest.
- Use k6 or Gatling for load testing API endpoints - Supertest is single-threaded and can't simulate concurrent user load.
Reference Files
https://github.com/ladjs/supertesthttps://docs.pact.io/