API Testing
Test Structure
What to Test
- •Happy path: Valid request → expected response
- •Validation: Invalid input → 400/422 with error details
- •Auth: Unauthenticated → 401; unauthorized → 403
- •Not found: Invalid ID → 404
- •Edge cases: Empty body, missing required fields, type mismatches
Request/Response Assertions
- •Status code matches expectation
- •Response body shape (keys present, types correct)
- •Error messages are present and meaningful
- •No sensitive data in responses (tokens, internal IDs if applicable)
Test Organization
code
tests/ ├── api/ │ ├── auth.test.ts │ ├── users.test.ts │ └── products.test.ts
Group by resource or feature. Use describe for endpoint, it for scenario.
Setup/Teardown
- •Use test database or mocks; never hit production
- •Seed minimal data per test when needed
- •Clean up created resources in
afterEachor use transactions
Example Pattern (supertest-style)
typescript
it('returns 400 when email is invalid', async () => {
const res = await request(app)
.post('/api/users')
.send({ email: 'invalid', name: 'Test' });
expect(res.status).toBe(400);
expect(res.body.error.details).toContainEqual(
expect.objectContaining({ field: 'email' })
);
});