Postman Tests and Scripts: Assertions, Chaining and Newman CLI

Postman Tests and Scripts: Assertions, Chaining and Newman CLI

Clicking Send and reading the response is manual testing. The moment you add a script that checks the status, the body and the headers on its own, your Postman collection becomes an automated test suite. Add Newman and it runs every night in CI without anyone opening Postman. This lesson covers the pm scripting API, the assertions you’ll use daily, JSON Schema validation, chaining, data-driven runs and Newman with HTML reports, all on the live practice API.

Quick answerPostman tests are JavaScript snippets in the Post-response script tab, written as pm.test('name', () => { pm.expect(...)... }) using the Chai assertion library. Pre-request scripts prepare data before sending. Values are passed between requests with pm.environment.set() / pm.collectionVariables.set(). The Collection Runner runs a collection with CSV/JSON data, and Newman (newman run collection.json -e env.json) runs it from the command line or a CI pipeline with CLI, JUnit and HTML reports.
Advertisement

Pre-request vs Post-response Scripts

Pre-request scriptPost-response script (tests)
RunsBefore the request is sentAfter the response arrives
Typical useGenerate data, timestamps, signatures; fetch a tokenAssertions; save values for later requests
LevelsCollection → folder → request (all run, in that order)Request → folder → collection
Real-life example: signed payment requests Payment partner APIs often require an HMAC signature header calculated from the body and a secret. A pre-request script computes it with CryptoJS.HmacSHA256 before every call, so testers never calculate signatures by hand.

The Assertions You’ll Use Every Day

// Status
pm.test('status is 200', () => pm.response.to.have.status(200));
pm.test('status is 2xx', () => pm.response.to.be.success);
pm.test('status is one of 200/201', () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));

// Response time
pm.test('responds under 1000 ms', () => pm.expect(pm.response.responseTime).to.be.below(1000));

// Headers
pm.test('JSON content type', () => {
  pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');
});
pm.test('has ETag', () => pm.response.to.have.header('ETag'));

// Body values
const json = pm.response.json();
pm.test('user is Asha Verma', () => {
  pm.expect(json.data.name).to.eql('Asha Verma');
  pm.expect(json.data.age).to.be.a('number').and.to.be.above(17);
  pm.expect(json.data.role).to.be.oneOf(['admin', 'editor', 'viewer']);
  pm.expect(json.data.email).to.match(/^[^@\s]+@[^@\s]+$/);
});

// Arrays
pm.test('every product is a book', () => {
  json.data.forEach(p => pm.expect(p.category).to.eql('books'));
});

// Negative / error format
pm.test('error has code and message', () => {
  pm.expect(json.error).to.have.all.keys('status', 'code', 'message');
});

Try the last pattern on a 404 response:

GEThttps://sqatools.in/wp-json/sqa-api/v1/users/999
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/users/999"
to.eql vs to.equal to.equal checks strict identity (fine for strings and numbers); to.eql compares objects and arrays deeply. Use eql for {...} and [...].
Advertisement

JSON Schema Validation in Postman

Postman includes a JSON Schema validator. Validate the whole structure in one assertion:

const userSchema = {
  type: 'object',
  required: ['id', 'name', 'email', 'role', 'age', 'active'],
  properties: {
    id:     { type: 'integer', minimum: 1 },
    name:   { type: 'string' },
    email:  { type: 'string' },
    role:   { enum: ['admin', 'editor', 'viewer'] },
    age:    { type: 'integer', minimum: 18 },
    active: { type: 'boolean' },
  },
};

// Built-in assertion: wrap the user schema because the API returns { "data": user }
pm.test('user matches schema', () => {
  pm.response.to.have.jsonSchema({ type: 'object', required: ['data'], properties: { data: userSchema } });
});

// Same check with the bundled Ajv library (shows detailed errors):
pm.test('user matches schema (Ajv)', () => {
  const Ajv = require('ajv');
  const ajv = new Ajv({ allErrors: true });
  pm.expect(ajv.validate(userSchema, pm.response.json().data), JSON.stringify(ajv.errors)).to.be.true;
});

Tip: the practice API publishes its real contract at GET /schema/user. Fetch it once, store it in a collection variable, and validate every user response against it.

Chaining Requests: A Full CRUD Flow

Create a folder “CRUD flow” with five requests and these scripts:

#RequestPost-response script
1POST {{baseUrl}}/objectspm.test('201', () => pm.response.to.have.status(201));
pm.collectionVariables.set('objId', pm.response.json().id);
pm.collectionVariables.set('etag', pm.response.headers.get('ETag'));
2GET {{baseUrl}}/objects/{{objId}}Assert 200 and name
3PATCH {{baseUrl}}/objects/{{objId}} with header If-Match: {{etag}}Assert 200 and version === 2
4DELETE {{baseUrl}}/objects/{{objId}}Assert 204
5GET {{baseUrl}}/objects/{{objId}}Assert 404

Controlling the flow

// Skip the rest of the run if login failed
if (pm.response.code !== 200) {
  pm.execution.setNextRequest(null);          // older versions: postman.setNextRequest(null)
}

// Jump to a specific request by name
pm.execution.setNextRequest('Cleanup - delete object');
Advertisement

Pre-request Scripts: Get a Token Automatically

Put this at collection level so every request has a valid token, fetched only when the old one is missing or expired:

const expiresAt = pm.collectionVariables.get('token_expires_at');
if (!expiresAt || Date.now() > Number(expiresAt) - 30000) {
  pm.sendRequest({
    url: pm.environment.get('baseUrl') + '/auth/login',
    method: 'POST',
    header: { 'Content-Type': 'application/json' },
    body: { mode: 'raw', raw: JSON.stringify({
      username: pm.environment.get('username'),
      password: pm.environment.get('password'),
    }) },
  }, (err, res) => {
    const body = res.json();
    pm.collectionVariables.set('access_token', body.access_token);
    pm.collectionVariables.set('token_expires_at', Date.now() + body.expires_in * 1000);
  });
}

Then set the collection’s Authorization to Bearer Token = {{access_token}}.

Advertisement

Data-Driven Testing with the Collection Runner

Run one request many times with different inputs from a CSV or JSON file. Example age-boundaries.csv for POST /validate/user:

name,email,age,expectedStatus
Asha,asha@example.com,17,422
Asha,asha@example.com,18,200
Asha,asha@example.com,100,200
Asha,asha@example.com,101,422

Request body uses data variables:

{ "name": "{{name}}", "email": "{{email}}", "age": {{age}} }

Test script reads the expected value from the same row:

pm.test(`age ${pm.iterationData.get('age')} -> ${pm.iterationData.get('expectedStatus')}`, () => {
  pm.response.to.have.status(Number(pm.iterationData.get('expectedStatus')));
});

In the Runner, select the request or folder, choose the data file, check the preview and click Run. Each CSV row is one iteration.

POSThttps://sqatools.in/wp-json/sqa-api/v1/validate/user
curl -i \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"Asha","email":"asha@example.com","age":17}' \
  "https://sqatools.in/wp-json/sqa-api/v1/validate/user"
Advertisement

Newman: Run Postman Collections from the Command Line

Newman is Postman’s command-line runner. It’s how collections run in Jenkins, GitHub Actions, GitLab CI or Azure DevOps.

# 1. Install (needs Node.js)
npm install -g newman newman-reporter-htmlextra

# 2. Export from Postman: collection (v2.1) and environment as JSON files

# 3. Run
newman run sqa-practice.postman_collection.json \
  -e sqa-practice.postman_environment.json \
  -d age-boundaries.csv \
  -r cli,junit,htmlextra \
  --reporter-junit-export results/junit.xml \
  --reporter-htmlextra-export results/report.html

# Useful options
#   --folder "CRUD flow"     run one folder only
#   -n 3                     run 3 iterations
#   --delay-request 200      wait 200 ms between requests
#   --bail                   stop on first failure
#   --env-var "password=$QA_PASSWORD"   inject secrets from CI

Newman exits with code 1 when any test fails, which fails the CI build: exactly what you want.

Newman in GitHub Actions

name: api-tests
on: [push, workflow_dispatch]
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 postman/sqa-practice.postman_collection.json \
            -e postman/sqa-practice.postman_environment.json \
            --env-var "password=${{ secrets.QA_PASSWORD }}" \
            -r cli,htmlextra --reporter-htmlextra-export report.html
      - uses: actions/upload-artifact@v4
        if: always()
        with: { name: newman-report, path: report.html }
Advertisement

Organising a Maintainable Postman Test Suite

  • Folders per resource, plus “Smoke”, “Negative” and “Flows”.
  • Reusable checks at collection level, e.g. a post-response script asserting every response is JSON and under 2 seconds.
  • Names that state the expectation: “PATCH object with stale If-Match – 412”.
  • No hardcoded ids or URLs; everything via variables.
  • Each flow creates and cleans up its own data.
  • Collections stored in Git (exported JSON) so changes are reviewed.

Reusable code across requests can be saved as a function in a collection variable or, in recent Postman versions, as package library scripts.

Postman vs Code-Based Automation

Postman + NewmanPlaywright (TypeScript)
Start-up speedVery fast, low codeNeeds project setup
Version control and reviewJSON exports (hard to diff)Normal code reviews
Complex logic, reuseLimitedFull language, fixtures, helpers
UI + API in one frameworkNoYes
Best forExploration, smaller suites, mixed-skill teamsLarge long-lived regression suites

Many teams use both: Postman for exploration and contract smoke tests, Playwright for the main regression suite (Module 6).

Advertisement

Interview Questions: Postman Scripts and Newman

What is the difference between pre-request and post-response scripts?

Pre-request scripts run before a request is sent to prepare data, headers, signatures or tokens. Post-response scripts run after the response arrives to make assertions and store values for later requests.

How do you write an assertion in Postman?

Use pm.test with a name and a function containing pm.expect or pm.response.to assertions, for example pm.test(‘status 200’, () => pm.response.to.have.status(200)).

Which assertion library does Postman use?

Chai’s BDD style (expect), exposed as pm.expect, plus Postman’s own pm.response.to helpers.

How do you validate JSON Schema in Postman?

Use pm.response.to.have.jsonSchema(schema) in recent versions, or the bundled Ajv library: create a validator, validate the parsed response and assert the result is true, printing ajv.errors on failure.

What is Newman?

The command-line collection runner for Postman. It runs exported collections with environments and data files, produces CLI, JUnit and HTML reports and returns a non-zero exit code on failures, which makes it suitable for CI/CD pipelines.

How do you do data-driven testing in Postman?

Use {{variables}} in the request, then run it in the Collection Runner or Newman with a CSV or JSON data file. Each row is an iteration, accessible in scripts through pm.iterationData.get().

How do you control the order of requests in a run?

Requests run in collection order by default; pm.execution.setNextRequest(‘name’) jumps to a specific request and setNextRequest(null) stops the run.

How do you send a request from inside a script?

Use pm.sendRequest with a URL or request object and a callback. It’s commonly used in pre-request scripts to fetch auth tokens.

How do you keep secrets out of shared Postman collections?

Store them as secret-type environment variables or in Postman Vault, keep real values only in “current value”, and inject them in CI with newman –env-var from the CI secret store.

How does Newman report failures to CI?

It exits with code 1 when any assertion fails or a request errors, causing the CI step to fail. JUnit XML reports can be published by the CI tool and HTML reports uploaded as build artifacts.

Advertisement
View the full API testing syllabus