Up to this point you've been a user of Postman — sending requests, reading responses, organising collections. This lesson promotes you to a tester. The Tests tab is where Postman stops being a request-builder and starts being an automated assertion engine. You'll write a few lines of JavaScript that run after every response, and Postman will tell you pass or fail in green or red. You learned the concepts of API assertions in the API Testing Masterclass — this lesson teaches you to drive them in Postman.
Where tests live
Open any saved request and click the Tests tab (the rightmost tab in the request builder, after Pre-request Script). You'll see an empty JavaScript editor. Anything you write here runs after the response is received and has access to the full response — status, headers, body — through Postman's pm object.
The editor's right sidebar lists Snippets: ready-to-paste templates for the most common assertions. Click any snippet and it inserts at the cursor. New testers should use snippets liberally; you'll outgrow them in a week.
Your first assertion
Open GET All Users from your JSONPlaceholder API Tests collection. Click the Tests tab. Paste:
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});Click Send. Then look at the response panel at the bottom and click the Test Results tab. You should see:
✓ Status code is 200
A green tick. Your first automated test in Postman, passing.
What just ran? pm.test() is the test wrapper. The first argument is a name (shown in the results); the second is a function that contains assertions. pm.response.to.have.status(200) is the assertion itself — it throws if the response status isn't 200, and pm.test catches the throw and records the test as failed. No throw, no failure, test passes.
Multiple tests per request
A single request can have many tests. Stack them in the Tests tab:
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
pm.test("Response time is under 500ms", function () {
pm.expect(pm.response.responseTime).to.be.below(500);
});
pm.test("Response is JSON", function () {
pm.response.to.be.json;
});
pm.test("Response is an array of users", function () {
const body = pm.response.json();
pm.expect(body).to.be.an("array");
pm.expect(body.length).to.be.above(0);
});Send. The Test Results tab now shows four results, one per pm.test block. Each test is independent — if one fails, the others still run. That's why you split assertions into named tests rather than stuffing them into one block: you want to know which property failed, not just that "something" did.
The end-to-end rhythm
Step back and look at the lifecycle Postman walks through every time you click Send.
Step 1 of 5
Write tests in the Tests tab
Add pm.test() blocks for each property of the response you want to assert. The script doesn't execute yet — it's just stored on the request.
That five-step rhythm is the entire mental model. Master it once and the rest of this chapter is just learning new assertions.
The pm object — what's available
Inside a Tests script, the pm object exposes the runtime. The pieces you'll use most:
pm.response— the full response.pm.response.code— numeric status (200, 404…).pm.response.status— reason phrase ("OK", "Not Found").pm.response.responseTime— milliseconds.pm.response.responseSize— bytes.pm.response.headers.get("Content-Type")— read a single header.pm.response.json()— parse the body as JSON. Throws if not JSON.pm.response.text()— body as a raw string.
pm.expect(value)— Chai-style assertion. Chain matchers off it:pm.expect(value).to.equal(expected); pm.expect(value).to.be.a("string"); pm.expect(array).to.include(item); pm.expect(object).to.have.property("name"); pm.expect(num).to.be.below(100);pm.response.to.have.status(200)— shorthand forpm.expect(pm.response.code).to.equal(200).pm.environment.get/set,pm.collectionVariables.get/set— read and write variables (lesson 3 of this chapter, and Chapter 4 use these heavily).pm.request— the request that was just sent (URL, method, body). Less common in tests; useful in pre-request scripts.
Snippets you should know by name
The right-hand snippet panel is your training wheels. The five you'll reach for repeatedly:
- Status code: Code is 200 — the basic status assertion.
- Response body: JSON value check — parses the body and asserts on a field.
- Response body: Contains string — string-search inside the raw body.
- Response headers: Content-Type header check — the standard JSON content-type assertion.
- Response time is less than 200ms — the latency budget assertion.
After a week of writing tests, you won't need the snippets — but they're a perfect crib sheet while you're learning the syntax.
A complete first-test set
Here's a five-test template you can paste onto any GET that returns an array of objects (e.g. JSONPlaceholder's /users):
pm.test("Status is 200", () => {
pm.response.to.have.status(200);
});
pm.test("Response time is under 500ms", () => {
pm.expect(pm.response.responseTime).to.be.below(500);
});
pm.test("Content-Type is JSON", () => {
pm.expect(pm.response.headers.get("Content-Type")).to.include("application/json");
});
pm.test("Body is a non-empty array", () => {
const body = pm.response.json();
pm.expect(body).to.be.an("array");
pm.expect(body.length).to.be.above(0);
});
pm.test("First item has expected fields", () => {
const first = pm.response.json()[0];
pm.expect(first).to.have.property("id");
pm.expect(first).to.have.property("name");
pm.expect(first).to.have.property("email");
});Five small tests; each one fails loudly if its specific concern breaks. That's the shape every endpoint test in this course will take.
Failure, on purpose
Change the status assertion to expect 999:
pm.test("Status is 999", () => {
pm.response.to.have.status(999);
});Send. The Test Results tab now shows a red ✗ next to that test with the failure message:
✗ Status is 999
AssertionError: expected response to have status code 999 but got 200
That's exactly what you'd see when a real assertion breaks. Always change a test once to make it fail before trusting it — a passing test you've never seen fail might just be never running.
⚠️ Common mistakes
- Calling
pm.response.json()on a non-JSON response. It throws and your test errors out (not just fails — errors). Guard withpm.expect(pm.response.headers.get("Content-Type")).to.include("application/json")first, or wrap in try/catch. - Naming every test "Test 1", "Test 2". The test name is what shows up when something fails at 3am. Name each test after the property it's protecting:
"Status is 200","Body is array","Email field present". - Stuffing every assertion into one
pm.test()block. When a single block has fiveexpects and one fails, the rest don't run and you only see the first failure. Split into onepm.test()per logical concern.
🎯 Practice task
Write your first test suite. 25-30 minutes.
- Open
GET All Usersin your collection. Paste the five-test template from earlier into the Tests tab. Send. Confirm all five pass. - Open
GET User by ID(/users/1). Adapt the five-test template — the body is now a single object, not an array. Changepm.expect(body).to.be.an("array")topm.expect(body).to.be.an("object"), and replace the array length check with field assertions on the object directly. - Open
POST Create Post. Add three tests: status is201, body has propertyid, andidis a number. - Open
DELETE Post. Add two tests: status is200(JSONPlaceholder returns 200 for DELETE; a strict API would return 204), and response body is an empty object. - Break a test on purpose. Change one of the status assertions to expect
999. Send. See the red failure message in the Test Results tab. Change it back. - Use a snippet. In any Tests editor, click the right-hand panel →
Response time is less than 200ms. Notice it inserts a completepm.testblock ready to use. - Stretch: add a sixth test to
GET All Usersthat asserts every user object has both anidand anemail. Usebody.forEach(...)inside onepm.test.
You can now write Postman tests with confidence. The next lesson goes deeper into the three big assertion families — status, body, and headers — and the patterns that hold up across real APIs.