API Testing Guide
What to Test in Every API Endpoint
| Category | Test Cases |
|---|---|
| Happy path | Valid input โ expected response body, correct status code |
| Validation | Missing required fields, wrong types, boundary values |
| Authentication | No token โ 401, expired token โ 401, invalid token โ 401 |
| Authorization | Correct user but wrong role โ 403, access other user's data โ 403 |
| Not found | Non-existent ID โ 404 |
| Idempotency | Repeated POST with same key โ same result, no duplicate |
| Concurrency | Race conditions on shared resources |
| Response schema | All expected fields present, correct types |
Integration Tests with Supertest (Node.js)
import request from 'supertest';
import app from '../app';
import { db } from '../db';
describe('POST /api/users', () => {
afterEach(() => db.users.deleteMany({})); // clean up
it('creates a user and returns 201', async () => {
const res = await request(app)
.post('/api/users')
.send({ name: 'Alice', email: 'alice@example.com' })
.expect(201)
.expect('Content-Type', /json/);
expect(res.body).toMatchObject({
id: expect.any(String),
name: 'Alice',
email: 'alice@example.com',
createdAt: expect.any(String)
});
});
it('returns 400 when email is missing', async () => {
const res = await request(app)
.post('/api/users')
.send({ name: 'Alice' })
.expect(400);
expect(res.body.error).toContain('email');
});
it('returns 409 when email already exists', async () => {
await db.users.create({ name: 'Alice', email: 'alice@example.com' });
await request(app)
.post('/api/users')
.send({ name: 'Bob', email: 'alice@example.com' })
.expect(409);
});
});
Newman (CLI) & Postman Automation
# Run Postman collection from CLI
newman run collection.json \
--environment staging.env.json \
--reporters cli,json \
--reporter-json-export results.json
# In CI/CD (GitHub Actions)
# - name: Run API tests
# run: |
# newman run tests/api-collection.json \
# --env-var "BASE_URL=${{ env.API_URL }}" \
# --env-var "API_KEY=${{ secrets.API_KEY }}"
# Postman test script example (in Tests tab)
pm.test("Status code is 200", () => {
pm.response.to.have.status(200);
});
pm.test("Response schema is valid", () => {
const schema = {
type: "object",
required: ["id", "name", "email"],
properties: {
id: { type: "string" },
name: { type: "string" },
email: { type: "string", format: "email" }
}
};
pm.response.to.have.jsonSchema(schema);
});
// Save token for subsequent requests
const token = pm.response.json().token;
pm.environment.set("AUTH_TOKEN", token);