REST API test automation for the public ReqRes demo API, built with Postman / Newman and wired into a Jenkins CI pipeline running Newman inside a custom Docker image.
This is a portfolio project demonstrating an API testing approach: reusable baseline assertions, real JSON-schema validation, request chaining, positive/negative/edge coverage, and containerised CI reporting.
ReqRes now gates its endpoints behind an API key. The anonymous tier allows only ~40 requests/day per IP, which a 42-request run exhausts immediately (you'll get 429 rate_limit_exceeded). A free account raises this to 250 requests/day and gives you a personal key.
- Create a free account and generate a key at https://app.reqres.in/api-keys.
- In Postman, open the ReqRes - Demo environment and set the
apiKeyvariable's current value to your key. Leave the saved/exported value empty so the key never lands in version control. - Make sure the ReqRes - Demo environment is selected (top-right) before running.
The key is sent as an x-api-key header, configured once at the collection level (Authorization tab → API Key → added to Header), so every request inherits it. No request hardcodes the key.
Security: the committed environment file ships with an empty
apiKeyon purpose. Keep your real key local only — never commit it. For CI, inject it as a secret (see the CI section).
42 requests across 8 folders, targeting the ReqRes demo endpoints (/api/users, /api/unknown, /api/login, /api/register):
| # | Folder | Focus |
|---|---|---|
| 1 | Users – List | Pagination, schema validation, ?delay=, avatar/email format checks |
| 2 | Users – Single | Single reads, 404 handling, malformed ids, chained read |
| 3 | Users – Create | POST echo behaviour, createdAt, id capture for chaining |
| 4 | Users – Update | PUT/PATCH, updatedAt, chained update |
| 5 | Users – Delete | 204 No Content contract, empty-body assertion |
| 6 | Resources | Color resource schema, hex validation, pagination, 404 |
| 7 | Auth – Register | Success, missing password (400), token capture |
| 8 | Auth – Login | Success, missing field validation, token type check |
Baseline assertions at the collection level. Response-time and JSON content-type checks live in the collection-level test script, so every request inherits them without duplication. Request-level scripts only add endpoint-specific assertions.
Real schema validation. User and resource objects are validated with tv4 (bundled in the Postman sandbox) against explicit JSON schemas, rather than probing individual fields with to.exist.
Request chaining via collection variables. listUserId, createdUserId and authToken are captured at runtime and reused downstream. Chained requests include pre-request fallbacks so each request stays runnable in isolation, while a full top-to-bottom run (Newman's default) exercises the real chain.
Coverage per resource. Each resource has positive, negative and edge-case requests — not just happy paths.
Authentication handled once, at the collection level. The x-api-key header is set on the collection's Authorization tab and inherited by every request, with the key value referenced from an environment variable ({{apiKey}}) rather than hardcoded — so the suite stays credential-free in version control.
Note on the demo API: ReqRes write endpoints (
POST/PUT/PATCH/DELETEon/api/users) echo the payload and do not persist data. Assertions target status codes, response shape and echoed values accordingly.
reqres-api-automation/
├── collections/
│ └── reqres-api-tests.postman_collection.json # the suite (import into Postman)
├── environments/
│ └── reqres.postman_environment.json # baseUrl + apiKey (empty in VCS)
├── Dockerfile.newman # postman/newman + htmlextra reporter
├── Jenkinsfile # CI pipeline (build image + run)
├── package.json # local Newman scripts
├── .gitignore
└── README.md
- Import
collections/reqres-api-tests.postman_collection.json. - Import
environments/reqres.postman_environment.json, select it, and setapiKeyto your key (see Setup). - Run the collection (Collection Runner), top to bottom.
Requires Node.js.
Newman reads the key from the environment file. Either set apiKey locally in
environments/reqres.postman_environment.json, or override it at runtime with
--env-var so nothing sensitive is written to disk:
# install Newman + the htmlextra reporter
npm install -g newman newman-reporter-htmlextra
# run, injecting the key at runtime (recommended)
newman run collections/reqres-api-tests.postman_collection.json \
-e environments/reqres.postman_environment.json \
--env-var "apiKey=$REQRES_API_KEY"
# or use the npm scripts (expect apiKey to be set in the env file)
npm test # console output only
npm run test:ci # JUnit + HTML reports (writes to newman-reports/)docker build -f Dockerfile.newman -t reqres-newman:ci .
docker run --rm -v "$(pwd):/etc/newman" -e REQRES_API_KEY reqres-newman:ci \
run collections/reqres-api-tests.postman_collection.json \
-e environments/reqres.postman_environment.json \
--env-var "apiKey=$REQRES_API_KEY" \
-r cli,htmlextra \
--reporter-htmlextra-export newman-reports/report.htmlThe Jenkinsfile defines a pipeline that:
- Checks out the repository.
- Builds a custom Newman image from
Dockerfile.newman(officialpostman/newman:6-alpineplus thehtmlextrareporter, which the base image does not include). - Runs the collection in that container, emitting three reporters:
cli(console),junit(consumed by Jenkins' JUnit plugin for pass/fail trends) andhtmlextra(archived as a build artifact).
The pipeline runs Newman via explicit docker build / docker run steps rather than agent { dockerfile }, because the Newman image's ENTRYPOINT ["newman"] conflicts with the way the Docker Pipeline plugin keeps an agent container alive. Calling newman run … directly keeps the entrypoint intact.
The pipeline targets a Docker-in-Docker Jenkins setup (DOCKER_HOST → tcp://docker:2376).
The key must never be committed. Store it as a Jenkins Secret text credential
(e.g. with ID reqres-api-key) and expose it to the run, then pass it to Newman
with --env-var:
environment {
REQRES_API_KEY = credentials('reqres-api-key')
}
// ... in the run step, add:
// --env-var "apiKey=$REQRES_API_KEY"This keeps the committed environment file credential-free while the live key is injected only at run time.
- JUnit XML →
newman-reports/junit-report.xml— surfaced natively in the Jenkins build (Test Result trend). - HTML (htmlextra) →
newman-reports/report.html— archived under build artifacts.
Postman · Newman · newman-reporter-htmlextra · Docker · Jenkins · JavaScript (pm.* API) · tv4 (JSON schema)
MIT