Postman interview question
How do you write tests with pm.test and pm.expect, and chain requests in Postman?
Short answer
Post-response scripts use pm.test with Chai-style pm.expect assertions on status, headers, body and response time. Chain requests by extracting values such as ids or tokens from one response into variables, then referencing them as {{var}} in later requests; pre-request scripts prepare data or fetch tokens.
Answer
Where scripts run
Each request (and each folder and collection) has two script slots:
- Pre-request: runs before the request is sent. Generate data, compute signatures, fetch a token.
- Post-response (the “Tests” tab in older versions): runs after the response arrives. Assertions live here.
Scripts are JavaScript running in Postman’s sandbox, with the pm object and Chai’s BDD syntax via pm.expect.
Writing assertions
pm.test("status is 201", () => {
pm.response.to.have.status(201);
});
pm.test("returns JSON", () => {
pm.expect(pm.response.headers.get("Content-Type")).to.include("application/json");
});
const body = pm.response.json();
pm.test("user fields are correct", () => {
pm.expect(body.id).to.be.a("string");
pm.expect(body.email).to.eql(pm.variables.get("email"));
pm.expect(body.roles).to.include("viewer");
});
pm.test("responds within 800 ms", () => {
pm.expect(pm.response.responseTime).to.be.below(800);
});
Each pm.test is reported separately, so one failing check does not hide the others. Keep test names descriptive; they appear in Newman and CI reports.
For schema checks, pm.response.to.have.jsonSchema(schema) validates the body against a JSON Schema object.
Chaining requests
A typical flow: create a user, read it, update it, delete it. The create request saves the id:
// Post-response of "Create user"
pm.test("created", () => pm.response.to.have.status(201));
pm.collectionVariables.set("userId", pm.response.json().id);
Later requests use it: GET {{baseUrl}}/users/{{userId}}.
Pre-request scripts generate unique data so runs do not collide:
pm.variables.set("email", `qa+${Date.now()}@example.com`);
Built-in dynamic variables such as {{$guid}}, {{$timestamp}} and {{$randomEmail}} also work directly in the request.
Fetching a token automatically
A collection-level pre-request script can call the token endpoint with pm.sendRequest and store the result, so every request gets a fresh token:
pm.sendRequest({
url: pm.environment.get("tokenUrl"),
method: "POST",
header: { "Content-Type": "application/x-www-form-urlencoded" },
body: {
mode: "urlencoded",
urlencoded: [
{ key: "grant_type", value: "client_credentials" },
{ key: "client_id", value: pm.environment.get("clientId") },
{ key: "client_secret", value: pm.environment.get("clientSecret") }
]
}
}, (err, res) => {
if (!err) pm.environment.set("token", res.json().access_token);
});
In practice, add a check so the token is only refreshed when it is near expiry. Postman’s built-in OAuth 2.0 auth helper is another option.
Controlling flow
pm.execution.setNextRequest("Request name") (formerly postman.setNextRequest) jumps to another request in a collection run, and pm.execution.skipRequest() in a pre-request script skips the current one. Use them sparingly: heavy branching makes collections hard to follow. Chained requests also create coupling, so keep chains short and put each workflow in its own folder.
What interviewers look for
- Correct pm.test / pm.expect syntax and assertions beyond the status code.
- Extracting values into the right variable scope to chain requests.
- Pre-request scripts for tokens and unique test data.
- Awareness of coupling and flow control in collection runs.
A strong answer covers
- Uses pm.test with pm.expect / pm.response assertions
- Validates body, headers and response time, not only status
- Chains requests by saving extracted values into variables
- Uses pre-request scripts for setup like tokens or dynamic data
- Controls flow or keeps tests independent (setNextRequest, ordering)