skip to content

In a Postman test script, what does `pm.response.to.have.status(200)` assert, and what else can `status` take?

level: juniorimportance: must knowfreq 82%

answer

  1. One matcher, two kinds of argument
  2. A string is not a code
  3. It compares the phrase, not the number
  4. statusCode and statusReason spell it out
  5. Response.code is numeric, Response.status is text

basics

~20 s

Postman's status matcher is polymorphic: hand it a number and it compares the reply's status code, hand it a string and it compares the reply's reason phrase instead. statusCode and statusReason are the single-purpose spellings.

solid answer

~40 s

`pm.response.to.have.status(200)` asserts the reply's **numeric status code**. The same matcher also accepts a string — `pm.response.to.have.status('Not Found')` — and then compares the reply's **reason phrase**, failing with `expected response to have status reason 'Not Found' but got 'OK'`. The dispatch is on argument type, so a string is never resolved back into a code. Two single-purpose matchers sit beside it: `statusCode(code)` reads only the number, `statusReason(reason)` reads only the phrase, and `statusCodeClass(digit)` compares only the code's leading digit. Everything before the matcher is chai grammar, so `pm.response.to.not.have.status(404)` negates cleanly. Watch the collision with the data property: `pm.response.code` holds the number and `pm.response.status` holds the reason phrase as a string, so `pm.response.status` is not the matcher and never holds 200.

code

javascript · 5 lines
javascript
pm.response.to.have.status(200);
pm.response.to.have.status('OK');
pm.response.to.have.statusCode(201);
pm.response.to.have.statusReason('Created');
pm.response.to.not.have.status(404);

go deeper

for a junior

Recall that status takes either a number or a string, and that a number is the ordinary case. Know that pm.response.code holds the number while pm.response.status holds the reason text.

for a middle

Explain the type dispatch inside status and name the single-purpose matchers behind it: statusCode for the number, statusReason for the phrase, statusCodeClass for the leading digit. Be able to read the failure messages each produces.

for a senior

Show judgment about which part of the status line a suite should depend on. Reason phrases vary between servers and intermediaries, so a suite that asserts them buys itself failures that say nothing about the API's behaviour.

for a principal

Own the convention across many collections: whether teams write status or the explicit statusCode and statusReason, whether class-level checks are allowed, and how that convention keeps assertion failures readable to whoever is on call.

## Where `status` sits on the chain In a Postman test script, `pm.response` is the reply wrapped as the SDK's `Response` object. The sandbox adds a `to` property to that object, and reading it hands back a **chai assertion** whose subject is the response. Everything after `to` is therefore ordinary chai grammar — `have`, `be` and `not` are chai's language chains — while the matchers on the end (`status`, `statusCode`, `statusReason`, `statusCodeClass`, `header`, `body`, `jsonBody`, `responseTime`) are contributed by the `chai-postman` plugin that the sandbox registers into chai before your script runs. `status` is the first link most people ever write: ```javascript pm.response.to.have.status(200); ``` ## `status` dispatches on the argument's type The matcher is **polymorphic**. It inspects what you handed it and behaves differently: - a **number** is read as an HTTP status code and compared with the reply's code; - a **string** is read as a reason phrase and compared with the reply's reason. So `pm.response.to.have.status('Not Found')` is not a mistyped code check — it is a reason-phrase check. Run it against a reply that came back 200 and it fails with `expected response to have status reason 'Not Found' but got 'OK'`. Negate the numeric form instead and the message stays in code language: `pm.response.to.not.have.status(404)` against a 404 fails with `expected response to not have status code 404`. That single detail is what the question is really probing. A candidate who thinks `status` only takes numbers will read a colleague's `status('Created')` as a bug, and a candidate who thinks a phrase is resolved into a code will expect `status('Created')` and `status(201)` to be interchangeable. They are not: one reads the number, the other reads the text. ## The single-purpose spellings `status` is a convenience over matchers that each do one job. In a suite other people read, the explicit spelling is usually kinder. | Matcher | Argument | What it reads off the reply | |---|---|---| | `status(code)` | number | the numeric status code | | `status(reason)` | string | the reason phrase | | `statusCode(code)` | number | the numeric status code only | | `statusReason(reason)` | string | the reason phrase only | | `statusCodeClass(digit)` | number | the leading digit of the code | `statusCodeClass(1)` against a 200 fails with `expected response code to be 1XX but found 200` — it never looks at the other two digits and it never looks at the phrase. ## The two values `status` can compare The code and the phrase are two separate properties on the SDK's `Response`: - `pm.response.code` — a **number**, the status code; - `pm.response.status` — a **string**, the reason phrase. That naming collision catches people. `pm.response.status` is *not* the matcher, and it does not hold a number. A script that writes `pm.expect(pm.response.status).to.eql(200)` compares a string with a number and fails forever. The matcher is reached through `pm.response.to`, never through `pm.response.status`. Where a server sends no reason text of its own, the SDK fills the property in with the standard name for that code, so the phrase is almost always populated — which makes an accidental phrase assertion pass or fail for reasons the author never intended. ## Which one to assert A reason phrase is human-readable text that accompanies the code. It is not something a client should lean on: two servers can answer the same code with different wording, and an intermediary can rewrite it. The code is the stable check; the phrase is a check on wording. 1. **Assert the code**, unless the wording itself is the thing under test. 2. **Prefer `statusCode` or `statusReason`** when a reviewer might otherwise wonder which branch of `status` you meant. 3. **Reach for `statusCodeClass`** when several codes are legitimately acceptable and pinning one would make the test brittle. 4. **Negate with chai's `not`** — `pm.response.to.not.have.status(500)` — rather than inverting the check by hand with an `if`. ## What this link does not cover `status` only ever reads the status line. Headers are the `header` matcher's business, the raw text and the parsed payload belong to `body` and `jsonBody`, and timing belongs to `responseTime`. There is no combined form that checks a code and a header in one call; each link on the chain looks at exactly one part of the reply, and you write one assertion per thing you care about.

  • A colleague writes `pm.response.to.have.status('201')` and the test always fails against a 201 reply. Why?
    The argument is a string, so `status` takes its reason-phrase branch and compares `'201'` with the reply's reason text, which is `Created`. Quoting turned a code check into a phrase check. Drop the quotes for `status(201)`, or say what you mean with `statusCode(201)`.
  • Why is asserting a reason phrase generally weaker than asserting a status code?
    The phrase is human-readable text that servers and intermediaries may word differently for the same code, and the SDK substitutes the standard name when none is sent. The code is the part of the status line clients are meant to branch on, so it is the stable assertion; assert the phrase only when the wording itself is under test.
  • How do you write the same check through `pm.expect` instead of `pm.response.to`?
    `pm.expect(pm.response).to.have.status(200)`. `pm.expect` is chai's `expect`, and `pm.response.to` is a getter that returns `chai.expect(pm.response).to`, so both spellings build the same assertion with the same matchers available on it.

saying these in an interview costs you the question

  • Believes status accepts only a numeric status code
  • Quotes the code, turning a code check into a phrase check
  • Thinks a reason phrase is resolved back into a code
  • Reads pm.response.status expecting a number
  • Claims status also inspects headers or the body