Postman Assertions
Assertions are what turn a Postman request into a test. The old question "did the request succeed?" becomes "is this response correct?" — right status, right fields, right types, right values, right structure.
This practice set gives the exercises and a solution for each. Every assertion below was run with Newman against a local test API; all 17 passed.
Where Assertions Go
Write them in a request's Scripts → Post-response tab (called Tests in older Postman). Each pm.test() is a named check that passes or fails on its own, using Chai's pm.expect() syntax:
pm.test('status is 200', () => pm.response.to.have.status(200));
const order = pm.response.json();
pm.test('order id is 101', () =>
pm.expect(order.id).to.eql(101)
);
Name tests by what they prove — the names are what you read in the Collection Runner, Newman output and CI reports.
The Sample Response
{
"id": 101,
"status": "SHIPPED",
"total": 129.5,
"currency": "INR",
"couponCode": null,
"notes": "",
"customer": {
"name": "Asha",
"address": {
"city": "Pune",
"zip": "411001"
}
},
"items": [
{
"sku": "BAG-1",
"name": "Backpack",
"price": 99.5,
"qty": 1
},
{
"sku": "LGT-2",
"name": "Bike Light",
"price": 15.0,
"qty": 2
}
],
"createdAt": "2026-09-20T10:15:30Z"
}
Core Validations (1–10)
| # | Exercise | Why it matters |
|---|---|---|
| 1 | Status code for success and failure | The first signal of right or wrong behaviour |
| 2 | Response time within the SLA | Early warning of slowness |
| 3 | Mandatory fields present | Clients break when fields disappear |
| 4 | Response headers | Content type, caching, security |
| 5 | Error responses | Clear codes and messages, no leaked internals |
| 6 | Null vs empty vs present | They mean different things to clients |
| 7 | Data types | A number sent as a string breaks strict clients |
| 8 | Nested values | Real payloads are nested |
| 9 | Arrays — every element | Checking only [0] misses bad items |
| 10 | Business rules (totals add up) | The response can be well-formed but wrong |
const order = pm.response.json();
pm.test('1. status is 200', () =>
pm.response.to.have.status(200)
);
pm.test('2. responds in under 2 s', () =>
pm.expect(pm.response.responseTime).to.be.below(2000)
);
pm.test('3. mandatory fields present', () =>
pm.expect(order).to.include.all.keys(
'id',
'status',
'total',
'customer',
'items'
)
); // extra fields allowed
pm.test('4. JSON content type and no-store caching', () => {
pm.expect(
pm.response.headers.get('Content-Type')
).to.include('application/json');
pm.response.to.have.header('Cache-Control', 'no-store');
});
pm.test('6. null vs empty vs present', () => {
pm.expect(order).to.have.property('couponCode');
pm.expect(order.couponCode).to.be.null;
pm.expect(order.notes).to.equal('');
});
pm.test('7. data types', () => {
pm.expect(order.id).to.be.a('number');
pm.expect(order.total).to.be.a('number');
pm.expect(order.items).to.be.an('array');
pm.expect(order.customer).to.be.an('object');
});
pm.test('8. nested value', () =>
pm.expect(order.customer.address.city).to.eql('Pune')
);
pm.test('9. every item is valid', () => {
pm.expect(order.items).to.have.lengthOf.above(0);
order.items.forEach(i => {
pm.expect(i.price).to.be.above(0);
pm.expect(i.qty).to.be.at.least(1);
});
pm.expect(
order.items.find(i => i.sku === 'LGT-2').qty
).to.eql(2);
});
pm.test('10. total matches the items', () => {
const sum = order.items.reduce(
(s, i) => s + i.price * i.qty,
0
);
pm.expect(order.total).to.be.closeTo(sum, 0.001);
});
Testing Error Responses
Exercise 5 uses a separate request for a missing order:
// GET /orders/999
const body = pm.response.json();
pm.test('5. 404 with a clear error', () => {
pm.response.to.have.status(404);
pm.expect(body.error).to.eql('ORDER_NOT_FOUND');
pm.expect(body.message).to.include('999');
pm.expect(pm.response.text())
.to.not.match(/Exception|Traceback|at com\./);
});
Tips From the Run
- Use
include.all.keysrather thanall.keysso an API adding a harmless new field doesn't break the test. - Check
Content-Typewithincludebecause servers can append a charset. - Compare decimals with
closeTorather thaneql. - Validate both positive and negative responses instead of checking only successful requests.
Advanced Validations (11–17)
pm.test('11. status is an allowed value', () =>
pm.expect([
'PLACED',
'SHIPPED',
'DELIVERED',
'CANCELLED'
]).to.include(order.status)
);
pm.test('12. timestamp is valid ISO-8601 and in the past', () => {
pm.expect(order.createdAt).to.match(
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/
);
pm.expect(
new Date(order.createdAt).getTime()
).to.be.below(Date.now());
});
const schema = {
type: 'object',
required: ['id', 'status', 'items'],
properties: {
id: {
type: 'integer'
},
status: {
type: 'string',
enum: [
'PLACED',
'SHIPPED',
'DELIVERED',
'CANCELLED'
]
},
items: {
type: 'array',
minItems: 1,
items: {
type: 'object',
required: ['sku', 'price', 'qty']
}
}
}
};
pm.test(
'13. matches the contract (JSON schema)',
() => pm.response.to.have.jsonSchema(schema)
);
On a product list sorted by price (GET /products?sort=price):
const body = pm.response.json();
const products = body.data;
const prices = products.map(p => p.price);
pm.test('14. sorted by price ascending', () =>
pm.expect(prices).to.eql(
[...prices].sort((a, b) => a - b)
)
);
pm.test('15. no duplicate ids', () =>
pm.expect(
new Set(products.map(p => p.id)).size
).to.eql(products.length)
);
pm.test('16. pagination metadata is consistent', () =>
pm.expect(products.length).to.be.at.most(body.totalItems)
);
pm.collectionVariables.set(
'capPrice',
products.find(p => p.title === 'Cap').price
);
// Next request: GET /products/3
pm.test('17. price is consistent between list and detail', () =>
pm.expect(
pm.response.json().price
).to.eql(
pm.collectionVariables.get('capPrice')
)
);
A Gotcha We Hit: Don't Declare a Variable Called data
The first version of the sorting script used:
const data = body.data;
Newman reported a SyntaxError in test-script for a line that otherwise looked like valid JavaScript.
In this test setup, data conflicted with a reserved name exposed by the Postman script sandbox. Renaming the variable to products fixed the problem.
If a script throws a SyntaxError that looks impossible, check variable names and the Postman sandbox context before assuming the JavaScript syntax itself is wrong.
Where to Put Common Assertions
Checks that apply to every request — response time, JSON content type, no stack traces — belong in the collection-level Post-response script, so each request only holds its own specific assertions.
More: Postman Scripting & Assertions.
Decide which assertions each endpoint really needs — positive, negative and edge cases — in the API Testing Scenario Lab.
Practice APIs
- Restful Booker — booking fields, dates, types, error responses.
- Fake Store API — product lists, sorting, list-vs-detail consistency.
- Swagger Petstore — schema checks against a published OpenAPI spec.
- GoRest — pagination headers and validation errors.
From Real Projects
I've worked with APIs at the level this page covers: CRUD operations, HTTP methods, JSON and XML formats, and extracting and validating values with JSON path. A good habit from that work: test the full create–read–update–delete cycle for a resource and check each response in detail. Testsigma supports web, mobile and API test automation, so understanding APIs was part of understanding the product I was testing. Group related checks into clearly named tests so failures are easy to read.
FAQs
Where do you write assertions in Postman?
In the request's Post-response (Tests) script, using pm.test() and pm.expect(); shared checks go in the collection-level script.
How do you check that mandatory fields exist?
Use:
pm.expect(body).to.include.all.keys(
'id',
'status'
);
The include form allows extra fields.
How do you validate every item in an array?
Loop with forEach and assert inside, or check a derived value such as a Set for uniqueness or a sorted copy for order.
How do you tell null from empty?
Use:
to.have.property('x')
for presence,
to.be.null
for null, and:
to.equal('')
or:
to.be.empty
for empty values.
How do you validate a response schema?
Use:
pm.response.to.have.jsonSchema(schema)
with a JSON Schema object.
Why does my valid script throw a SyntaxError?
You may be redeclaring a reserved sandbox name such as data. Rename the variable and check the surrounding Postman script context.