skip to content

In Postman, why does `pm.response.to.have.responseTime.below(200)` work without calling `responseTime()`?

level: seniorimportance: should knowfreq 42%

answer

  1. One form checks presence, the other compares
  2. Reading it bare changes what is asserted about
  3. The failure message names a number, not the reply
  4. responseSize reads exactly the same way
  5. One sample, one call, milliseconds

basics

~20 s

Read without parentheses, Postman's responseTime matcher retargets the assertion's subject to the recorded duration in milliseconds, so a numeric comparison such as below applies to that number. Invoked as responseTime(), it instead asserts the property is present.

solid answer

~40 s

`responseTime` is usable both ways. **Invoked** — `pm.response.to.have.responseTime()` — it asserts the response has a recorded `responseTime` at all, failing with a message that the response has no such property. **Read bare** — `pm.response.to.have.responseTime.below(200)` — it swaps the assertion's subject from the response to the recorded number, so the comparison that follows applies to the duration. You can see the swap in the failure text: it reads `expected 200 to be below 100`, naming the number rather than the response. The duration comes from the SDK's `responseTime` property on the reply, recorded in milliseconds. `responseSize` behaves the same way, which is why `responseSize.below(...)` reads identically.

code

javascript · 2 lines
javascript
pm.response.to.have.responseTime();
pm.response.to.have.responseTime.below(200);

go deeper

for a junior

Recall that responseTime can be read without parentheses and that a numeric comparison follows it. Know that the number is a duration in milliseconds for this one call.

for a middle

Explain that the bare read makes the recorded duration the subject of the assertion, which is why the numeric comparison applies, while the invoked form asserts only that a duration was recorded.

for a senior

Show you have lived with flaky timing assertions. Argue for where latency belongs, what a threshold in a correctness suite really claims from one sample, and how a red build gets misread by whoever sees it first.

for a principal

Own the policy: whether functional suites may gate on timing at all, what a guardrail ceiling is for, and where performance evidence is actually produced so teams stop inferring it from single-request assertions.

## Two ways to write the same link Most matchers on Postman's response chain are called: `status(200)`, `header('Content-Type')`, `jsonBody('data.id', 7)`. `responseTime` is one of the few that is useful **both** invoked and read bare, and the two forms assert different things. ```javascript pm.response.to.have.responseTime(); // the property is present pm.response.to.have.responseTime.below(200); // the recorded number is under 200 ``` Interviewers ask this because the second line looks like a mistake — a matcher used without parentheses that nevertheless keeps chaining — and explaining why it works shows you understand what an assertion chain actually carries. ## What the invoked form asserts Called with parentheses, `responseTime()` asserts that the response **has** a recorded response time. Against a response constructed without one, the failure names the missing property directly: it says the response was expected to have property `responseTime`. That is a presence check and nothing more; it says nothing about how long the call took. This is occasionally useful — a smoke check that timing was captured at all — but it is not what most suites want. ## What the bare form does Read without parentheses, `responseTime` **retargets the assertion's subject**. Before it, the subject is the response object; after it, the subject is the number recorded on the response. Whatever numeric comparison you chain next therefore applies to the duration, not to the reply. The proof is in the failure message. Assert `responseTime.below(100)` against a reply recorded at 200 and it reports `expected 200 to be below 100` — the message names a bare number. If the subject had still been the response, the message would have described the response. | Form | Subject after the link | What is asserted | |---|---|---| | `responseTime()` | the response | a recorded duration exists | | `responseTime.below(n)` | the recorded number | that duration is under `n` | The same shape appears on `responseSize`, so `responseSize.below(50)` fails with `expected 51 to be below 50`. Recognising the pattern once tells you how to read both. ## Where the number comes from The duration is the SDK's `responseTime` property on the reply, recorded in **milliseconds** — the runtime computes it around the call. It is a single measurement of a single request: no averaging, no percentile, no aggregation across iterations. A matcher cannot make it into a statistic, and nothing about the assertion causes the request to be retried or re-timed. ## Using it responsibly in a suite This is where senior judgment shows. A latency assertion inside a functional suite is a **single sample** taken on infrastructure you usually do not control, mixed in with tests whose job is correctness. The failure modes are unhelpful: - **It flaps.** One slow scheduling hiccup, one cold cache, one noisy build agent, and a correctness suite goes red for a reason that has nothing to do with correctness. - **It hides.** A threshold loose enough not to flap is usually loose enough to miss the regression you cared about. - **It misattributes.** The red build says the API is broken when the honest statement is that one call was slow once. Reasonable positions to defend: 1. **Keep a generous ceiling as a guardrail**, set well above normal so it only fires on pathological hangs, and treat it as a smoke signal rather than a performance budget. 2. **Keep timing out of the correctness suite entirely** and measure latency where samples, percentiles and load are actually modelled. 3. **Assert presence, not duration** — `responseTime()` — when all you need is proof that timing was captured. What does not survive scrutiny is a tight per-request threshold in a functional collection: it is a performance claim made from one sample, and it will spend more of the team's attention on retries than on defects. ## The thing to say out loud The mechanical answer is that the bare read changes the assertion's subject to the number so chai's numeric comparison can apply; the invoked call asserts the property exists. The judgment answer is that knowing how to write a latency assertion is not the same as it being wise to put one in a correctness suite, and an interviewer asking this question is usually listening for both halves.

  • How can you tell from a failure message which of the two forms was used?
    The invoked form fails by naming the missing property on the response — it complains the response was expected to have `responseTime`. The bare form fails with a plain numeric comparison such as `expected 200 to be below 100`, which names the duration alone. The subject in the message tells you which link you were on.
  • Would you put a per-request latency assertion in a functional collection that gates a build?
    Generally no. It is one sample on shared infrastructure, so a tight threshold flaps and a loose one misses regressions, and either way a red build blames correctness for a timing blip. A very generous ceiling as a hang guardrail is defensible; real latency work belongs where load and percentiles are modelled.

saying these in an interview costs you the question

  • Thinks the bare form is a syntax error
  • Believes responseTime averages across iterations
  • Expects the assertion to retry a slow request
  • Treats one sample as a performance measurement
  • Cannot say what the invoked form asserts