Collections
Requests grouped by feature, so the suite reads like the API's own map.
The UI is only as stable as the APIs underneath it. I use Postman to pin down every critical contract (status, shape, speed and auth) and run those checks as a gate in CI, so a broken API fails the build before a UI test has to find it.
pm.* with ChaiFour layers turn one-off API calls into a regression suite the whole team can run.
Requests grouped by feature, so the suite reads like the API's own map.
{{baseUrl}}, tokens and IDs swap per environment, so one suite covers dev, staging and prod.
pm.test assertions on status, schema, timing and headers, and they chain values into the next call.
Newman runs the collection on every pull request and publishes a report. A red run blocks the merge.
Pick a failure, send the request, and see which assertion stops it. Each of these is a bug I'd want caught before a UI test ever runs.
Inject a fault
Press Send to run the suite.
Post-response scripts for the assertions, a schema to lock the contract, and one CI step to enforce it.
// Post-response script on GET /users/:id
pm.test("status is 200", () => {
pm.response.to.have.status(200);
});
pm.test("responds in under 800 ms", () => {
pm.expect(pm.response.responseTime).to.be.below(800);
});
pm.test("content-type is JSON", () => {
pm.response.to.have.header("Content-Type", /application\/json/);
});
pm.test("user matches the contract", () => {
const user = pm.response.json();
pm.expect(user).to.have.all.keys("id", "name", "email", "role");
pm.expect(user.email).to.match(/^[^@\s]+@[^@\s]+$/);
});
// Chain: hand the id to the next request in the collection
pm.collectionVariables.set("userId", pm.response.json().id);
// Lock the response shape: extra or missing fields fail the run
const userSchema = {
type: "object",
required: ["id", "name", "email", "role"],
additionalProperties: false,
properties: {
id: { type: "integer" },
name: { type: "string", minLength: 1 },
email: { type: "string", format: "email" },
role: { enum: ["admin", "editor", "viewer"] },
},
};
pm.test("response matches the user schema", () => {
pm.response.to.have.jsonSchema(userSchema);
});
# .github/workflows/api-tests.yml: runs on every pull request
name: API contract tests
on: [pull_request]
jobs:
newman:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install -g newman newman-reporter-htmlextra
- run: |
newman run collections/users.postman_collection.json \
-e environments/staging.postman_environment.json \
--reporters cli,htmlextra \
--reporter-htmlextra-export reports/api.html
- uses: actions/upload-artifact@v4
if: always()
with:
name: api-report
path: reports/api.html
API checks run before the slower UI suites. A contract failure is cheaper to find here.
If a bug can be caught at the API layer, catching it in a UI test is slower, flakier and harder to debug.