skip to content

In a Postman script, how many results does one pm.test block containing five pm.expect calls report?

level: middleimportance: must knowfreq 76%

answer

  1. The block is the reporting unit
  2. One record regardless of expectation count
  3. Single error slot, single passed flag
  4. First throw unwinds the rest
  5. name, passed, skipped, error, index

basics

~20 s

Exactly one. A pm.test block is the reporting unit: it emits a single record carrying a name, a passed flag, a skipped flag, an error slot and an index, however many pm.expect calls sit inside it.

solid answer

~40 s

One. `pm.test(name, fn)` builds a single assertion record and then runs `fn` inside a try/catch; the record is emitted once, when the block finishes. Its fields are `name`, `passed`, `skipped`, `error`, `index` and `async` — there is one `error` slot and one `passed` flag, not a list. So five `pm.expect` calls in one block collapse into one pass or one fail. Because the body is a single try, the **first** throw unwinds the rest of the function: the later expectations never execute and the record carries only the first error. If you want each claim reported separately, write a separate `pm.test` block per claim and name each block after the claim it makes.

code

javascript · 5 lines
javascript
pm.test('order is created', function () {
    pm.expect(pm.response.code).to.eql(201);
    pm.expect(pm.response.json().id).to.be.a('string');
    pm.expect(pm.response.json().total).to.be.above(0);
});

go deeper

for a junior

Recall that a check lives inside pm.test(name, fn) and that the name you pass is what shows up in the report. Know that one block equals one reported line.

for a middle

Explain the record's fields — name, passed, skipped, error, index — and why a single try/catch means the first throw skips the rest of the body. Be able to say when to split blocks.

for a senior

Show judgment about granularity: which claims deserve their own line, how naming makes a failure diagnosable from the report alone, and why ordering inside a block decides what a failing run tells you.

for a principal

Own the convention across a collection: a naming scheme that survives the failure roll-up, a house rule on block granularity, and the tradeoff between report resolution and script volume.

## The block, not the expectation, is the unit `pm.test(name, fn)` is the function the Postman sandbox exposes for writing a check. Calling it does exactly two things: it builds **one assertion record**, and it invokes `fn`. The record is handed to the sandbox's assertion channel once, when the block finishes. However many `pm.expect(...)` calls the body holds — one, five, or fifty — the reporting surface sees a single line for that block. That split is the whole design. `pm.expect(...)` is an assertion-library call: it throws when the claim is false and returns nothing interesting when it is true. On its own a throw is just an error. It is `pm.test` that converts "did the body throw or not" into a **named, numbered, reportable verdict** that something outside the script can count. ## What one record carries The sandbox builds the record *before* it runs your function, so the block has an identity even if the body explodes on its first line: | field | what the sandbox puts there | |---|---| | `name` | the first argument, coerced with `String(name)` | | `passed` | `true` unless the body threw, or an async callback was handed an error | | `skipped` | `true` only for a block created by `pm.test.skip` | | `error` | the thrown value, or `null` | | `index` | a counter starting at `0` for each script execution, incremented per block | | `async` | `true` when the block's function declared a callback parameter | Notice what is **absent**: there is no count of expectations, no array of errors, no per-assertion breakdown. One `error` slot. One `passed` flag. That is the resolution at which a Postman script reports, and it is fixed by the shape of this record — no amount of extra `pm.expect` calls raises it. ## The first throw ends the body The synchronous form runs your function inside a single try/catch. That has a consequence people underestimate: the **first** failing expectation unwinds the rest of the function. Imagine one block that checks the status code, then a header, then three fields of the payload. The service returns a `500` with an error page. The status expectation throws, and: - the header check never runs; - the three payload checks never run; - the record's `error` holds the status failure and nothing else; - the report shows one failed line, so a reader cannot tell whether the payload was also wrong. Ordering inside a block is therefore load-bearing. Put the cheapest and most fundamental claim first, because everything after it is conditional on it. A block that asserts a body field before asserting the status code will report a confusing `undefined` error whenever the call fails outright. ## Sizing a block There is no rule that forces one expectation per block, so the choice is yours to justify: 1. **One claim, one block** when you want each claim's verdict reported on its own line and want the report to say which claim broke without anyone opening the run. 2. **Several expectations in one block** when they are only meaningful together — narrowing a value after proving the field exists, for example, where reporting the second failure separately would be noise. 3. **Never** wrap an entire response's worth of unrelated claims in a single block named after the request. You get one bit of information back for a lot of code. ## Names are the handle a reader gets The name is not decoration. The Postman runtime collects the names of blocks whose `passed` is `false` and joins them into one error it labels `AssertionFailure`. That joined string is often all a reader sees first. A block named `"Test 1"` tells them nothing; `"status is 201"` tells them what broke before they open anything. Two blocks sharing a name are indistinguishable in that roll-up, so names should be unique within a script. ## The counter `index` is assigned when the block starts, not when it finishes, and the counter is per script execution — a pre-request script and a test script each start their own numbering at `0`. `pm.test.index()` returns the current value, i.e. how many blocks have been created so far in this execution. It is a position, not a score: it says nothing about pass or fail.

  • If the second of five expectations in one block fails, what does the record say about the remaining three?
    Nothing. The body runs in one try/catch, so the throw unwinds the function and expectations three through five never execute. The record carries `passed: false` and the single first error. The report cannot distinguish "the rest were fine" from "the rest were never attempted", which is the main cost of grouping.
  • What does pm.test.index() return, and is it a count of passing blocks?
    It returns the block counter for the current script execution — how many assertion records have been created so far, starting from `0`. It counts blocks, not successes: failed and skipped blocks increment it exactly like passing ones. Each script execution starts its own numbering, so a pre-request script's indices do not continue into the test script.

A pm.test block is a ballot box, not a ballot: however many votes you drop in, the outside world reads one result off the lid.

saying these in an interview costs you the question

  • Claims each pm.expect call produces its own reported result
  • Believes all expectations run even after one throws
  • Thinks the record holds a list of every error raised
  • Names blocks Test 1, Test 2 with no claim in the name
  • Puts a payload-field check before the status-code check