skip to content

Which built-in helper functions can the `Scenario` name of a Karate mock feature call, and what do you do when none of them expresses the match you need?

level: juniorimportance: should knowfreq 44%

answer

  1. A handful of functions, not a DSL
  2. Path, method, type, accept, header, param, body
  3. Two of them return values, not booleans
  4. The name is just JavaScript
  5. Request variables are the escape hatch

basics

~20 s

Karate puts eight helpers in scope for a mock scenario name: pathMatches, methodIs, typeContains, acceptContains, headerContains, paramValue, paramExists and bodyPath. The name is JavaScript, so when none fits you write an expression over the request variables.

solid answer

~40 s

A mock scenario name is evaluated with a small set of helper functions already in scope: `pathMatches(pattern)` for the path (and it fills `pathParams`), `methodIs(name)` for a case-insensitive method check, `typeContains(text)` and `acceptContains(text)` for substring tests on `Content-Type` and `Accept`, `headerContains(name, value)` for a substring test on any value of one header, `paramValue(name)` and `paramExists(name)` for query and form parameters, and `bodyPath(expr)` to pull a value out of the request body with JsonPath, or with XPath when the expression starts with `/`. Karate 2.x adds `headerValue(name)`; it does not exist in 1.5.2. Because the name is **plain JavaScript**, these compose with `&&`, `||` and `!` — and when no helper fits you drop to the request variables directly (`requestPath`, `requestUri`, `requestMethod`, `requestHeaders`, `requestParams`, `request`) instead of registering a new matcher type.

code

gherkin · 7 lines
gherkin
Scenario: pathMatches('/cats') && methodIs('post') && typeContains('xml')
* def response = <cat><id>1</id></cat>
* def responseStatus = 201

Scenario: pathMatches('/cats') && methodIs('post')
* def response = { id: 1 }
* def responseStatus = 201

go deeper

for a junior

Learn the four you will use daily — pathMatches, methodIs, paramExists and typeContains — and remember the name is JavaScript so they join with &&.

for a middle

Know which helpers return booleans and which return values, and be able to rewrite any of them as a plain expression over the request variables.

for a senior

Judge when a condition has outgrown a scenario name and belongs in the body, and keep version-only helpers out of features that must run on both lines.

for a principal

Weigh the trade the design makes: unlimited matching power with no schema and no tool that can prove a stub is unreachable.

## The helpers in scope The mock handler puts a fixed set of functions into the engine before it evaluates any scenario name, so they are available both in the name (to route) and in the steps below it (to process): | Helper | Answers | Returns | |---|---|---| | `pathMatches(pattern)` | does the path fit this shape, with `{name}` placeholders | boolean, and fills `pathParams` | | `methodIs(name)` | is this the HTTP method — case-insensitive, so `'get'` is fine | boolean | | `typeContains(text)` | does the `Content-Type` header contain this substring | boolean | | `acceptContains(text)` | does the `Accept` header contain this substring | boolean | | `headerContains(name, value)` | does any value of this header contain this substring | boolean | | `paramExists(name)` | is this query or form parameter present | boolean | | `paramValue(name)` | the first value of that parameter, or `null` | string | | `bodyPath(expr)` | a value from the request body by JsonPath, or XPath when the expression starts with `/` | any, `null` on failure | `pathParams` sits alongside them as a **map, not a function** — it is the output of a successful `pathMatches()` call, not something you call yourself. ## Composition, not configuration Every one of those is an ordinary function call inside an ordinary JavaScript expression, which is the whole point of the design. There is no matcher object to build and nothing to register, so routing conditions are assembled with the operators the language already has: ```gherkin Scenario: pathMatches('/cats/{id}') && methodIs('get') && acceptContains('json') * def response = cats[pathParams.id] Scenario: pathMatches('/cats') && methodIs('post') && bodyPath('$.name') == 'Billie' * def response = { id: 1, name: 'Billie' } * def responseStatus = 201 ``` Two of the helpers return values rather than booleans — `paramValue()` and `bodyPath()` — so they belong in a **comparison**, never on their own. A name ending in `&& paramValue('type')` yields a string, and a string is not a match. ## When no helper fits The escape hatch is the language, not a plugin. The request is already in scope as variables, so anything you can express in JavaScript is a legal matcher: - `requestPath.startsWith('/legacy/')` — a prefix, which `pathMatches()` cannot do; - `requestPath.split('/').length > 4` — depth; - `requestUri.indexOf('debug') != -1` — anything in the path *or* the query string, since `requestUri` keeps the query string and `requestPath` does not; - `requestHeaders['x-tenant'][0] == 'acme'` — an exact header value rather than a substring; - `request.type == 'cat' && request.tags.length > 2` — the parsed body directly, which is usually clearer than `bodyPath()` for JSON; - `!pathMatches('/health')` — negation, to keep one probe path out of a broad stub. The variables available to a name in both released lines are `request` (the parsed body), `requestBytes`, `requestUrlBase`, `requestPath`, `requestUri`, `requestMethod`, `requestHeaders`, `requestParams` and `requestParts`. ## The version split to keep straight `headerValue(name)` — returning one header's value as a string instead of a substring test — is a **Karate 2.x** helper. It is not registered in 1.5.2, and a scenario name that calls it there throws while being evaluated, which the handler treats as *did not match*, so the stub simply never fires. On 1.5.2 the equivalents are `headerContains('authorization', 'Bearer ')` for a substring test or reaching into `requestHeaders` for an exact one. ## A note on what the helpers do not do Each helper is deliberately shallow, and knowing where each one stops saves an afternoon: - `typeContains('json')` is a **substring** test, so it also matches `application/ld+json` and any charset suffix — convenient, and occasionally too generous; - `headerContains(name, value)` is a substring test too, across **any** value of a repeated header, so it cannot express "this header equals exactly this"; - `paramValue()` returns only the **first** value of a repeated parameter, and `null` when it is absent; - `bodyPath()` swallows its own failures and returns `null` rather than throwing, so a wrong path looks the same as a missing field; - `methodIs()` compares case-insensitively, which is why `methodIs('get')` and `methodIs('GET')` are equivalent. ## Interview framing Nobody is checking whether you can recite eight names. What the question is really probing is whether you understand that Karate's mock has **no matcher DSL at all** — it hands you a handful of convenience functions over a JavaScript expression, and everything beyond them is code you write in place. Candidates who have used stub-server products often look for the equivalent of a matcher plugin; the honest answer is that there is nothing to plug in, and that this is a deliberate trade: complete flexibility, no schema, and no tooling that can tell you a condition is unreachable.

  • In a Karate mock, when would you use `bodyPath('$.name')` rather than `request.name`?
    For XML, where `bodyPath('/cat/name')` runs an XPath, and for deep or filtered JsonPath expressions. For plain JSON, `request.name` reads the parsed body directly and is clearer. Both return `null` rather than throwing when the path is missing, so either way compare the result instead of relying on it being truthy.
  • What is the difference between `requestPath` and `requestUri` in a Karate mock scenario name?
    `requestPath` is the path only, with the query string removed; `requestUri` is everything after the base URL, query string included. Match on `requestPath` for routing and reach for `requestUri` only when the query string itself is part of the condition — otherwise a stub can quietly stop matching as soon as a client appends a parameter.

saying these in an interview costs you the question

  • Looks for a matcher class or plugin to register
  • Uses paramValue on its own as a condition
  • Thinks typeContains does an exact header comparison
  • Believes pathParams is a function you call
  • Assumes headerValue exists in every Karate version
  • Says the helpers only work inside the scenario body