skip to content

In a Karate feature file, what forms can the left-hand side of a `match` step take, and what does a bare `$` refer to there?

level: juniorimportance: must knowfreq 82%

answer

  1. Four accepted shapes, not one
  2. Leading identifier is the variable
  3. One character means the response
  4. Parentheses switch to JavaScript
  5. Dollar prefix optional on the left

basics

~20 s

The left side of a Karate match step is a variable name, a JsonPath or XPath rooted at a variable such as response.name, a function or method call, or parenthesised JavaScript. A bare $ stands for the response, and a left side that starts with / is a bare XPath rooted there too.

solid answer

~50 s

`match` is a built-in step, so the whole assertion lives in the feature file with no step definition behind it. Karate accepts four shapes on the left: a plain variable name (`match cat == {...}`), a *named* JsonPath or XPath rooted at a variable (`match response.name == 'Billie'`, `match cat.kittens[*].id == [23, 42]`), a function or method call (`match foo.bar() == 3`), or anything wrapped in parentheses, which is evaluated as JavaScript (`match (foo + bar) == 'ab'`). A left side that is exactly `$`, or that starts `$.` or `$[`, is rooted at the `response` variable, so `match $.name == 'Billie'` and `match response.name == 'Billie'` do the same thing. A left side that starts with `/` is a bare XPath and is rooted at `response` the same way. You never need a `$` in front of a variable name on the left — the JsonPath is implied there, and the no-dollar form is the documented style.

code

gherkin · 30 lines
gherkin
* def cat =
  """
  {
    name: 'Billie',
    kittens: [
      { id: 23, name: 'Bob' },
      { id: 42, name: 'Wild' }
    ]
  }
  """

# 1. a variable name - compares the whole value
* def expected = { name: 'Billie', kittens: [{ id: 23, name: 'Bob' }, { id: 42, name: 'Wild' }] }
* match cat == expected

# 2. a named JsonPath rooted at a variable
* match cat.name == 'Billie'
* match cat.kittens[0].name == 'Bob'

# the two-token form: variable, then a full JsonPath
* match cat $.kittens[*].name == ['Bob', 'Wild']

# 3. a function or method call
* def firstId = function(c){ return c.kittens[0].id }
* match firstId(cat) == 23

# 4. parentheses - evaluated as JavaScript
* def a = 1
* def b = 2
* match (a + b) == 3

go deeper

for a junior

Remember the everyday shape: the variable name, then the path into it, then the comparison. Learn that a lone $ means the last response so you can read other people's feature files.

for a middle

Explain the split: Karate takes the leading identifier as the variable and hands the rest to the JsonPath engine as $ plus the remainder. Know the two-token form and the parentheses escape hatch.

for a senior

Steer a team toward the documented style — no dollar on the left, parentheses only where a path genuinely cannot express the check — so assertions stay greppable and reviewers can see what is being selected.

for a principal

The reason there are four shapes is that the assertion language has no compile step: the shape is settled at run time, mostly from the step text but partly from what the leading variable holds. Weigh that flexibility against the reviewability of a suite where any line can quietly become JavaScript.

## The left side is part of the feature file Karate has **no step definitions**. There is no glue class to hop into, no regex registry, no `@Given` method that receives a captured string. `match` is built into the runtime, which means the thing you are selecting and the value you expect both sit in the `.feature` text, and the runtime has to work out what you meant from that text — and, for a dotted left side, from what the leading variable turns out to hold. Karate's documentation lists exactly four shapes the left-hand side may take: 1. **A variable name** — `match cat == { name: 'Billie' }` compares the whole variable. 2. **A "named" JsonPath or XPath rooted at a variable** — `match response.name == 'Billie'`, `match cat.kittens[*].id == [23, 42]`, `match response..username contains 'Bret'`. 3. **A function or method call** — `match foo.bar() == 3` or `match foo.bar('hello').baz == 1`. 4. **Anything wrapped in parentheses**, evaluated as JavaScript — `match (foo + bar) == 'ab'`, `match (1 == 2) == false`. Shape 2 is the one you write all day, and it is why the left side reads like a path rather than an expression. Two more leading characters widen that list in practice. A left side beginning with `/` is a **bare XPath**, rooted at `response` exactly the way a bare `$` is — `match /cat/name == 'Billie'`. A left side beginning with `[` or `{` is a **JSON literal**: Karate wraps it in parentheses for you and hands it to the JavaScript engine, which is shape 4 under another spelling. So "the left side starts with the variable name or with `$`" is a rule about a *path* on the left, not about the left side as a whole. ## How a path is split For a named JsonPath, Karate takes the leading identifier as the **variable** and everything after it as the **path**, prefixed with `$`. So: | You write | Variable | JsonPath applied | |---|---|---| | `response.name` | `response` | `$.name` | | `cat.kittens[*].id` | `cat` | `$.kittens[*].id` | | `foo[0].bar` | `foo` | `$[0].bar` | | `cat` | `cat` | `$` (the whole value) | There is also a two-token form where you name the variable and then give a full JsonPath, separated by a space: `match cat $.kittens[*].name == ['Bob', 'Wild']`. That is useful when you want to write pure JsonPath, or when the path starts with something the single-token split would not handle. ## `$` is the response A left side that is exactly `$`, or begins `$.` or `$[`, is rooted at the `response` variable — the one Karate auto-binds after every HTTP call, alongside `responseStatus`, `responseHeaders` and `responseTime`. These pairs are equivalent: ```gherkin * match $ == { name: 'Billie' } * match response == { name: 'Billie' } * match $.name == 'Billie' * match response.name == 'Billie' ``` The `$` form is a convenience for the common case of asserting straight against the last response. Once you are selecting out of some other variable, name it: `match cat.name == 'Billie'`. ## You do not need `$` before a variable name On the **left** of `match`, the JsonPath context is implied, so `match $cat.name == 'Billie'` and `match cat.name == 'Billie'` resolve the same way. Karate accepts the leading `$` there but it buys you nothing, and the documentation is explicit that none of its own examples use it on the left — the no-dollar form is the house style. The `$variable` form earns its keep somewhere else: on the **right**-hand side and in other expression positions, where a bare `data[*].a` is not a path context. `match foo[*].a == $data[*].a` is the idiomatic way to compare two selections. ## When it is not a path at all Because the left side can also be JavaScript, there is an escape hatch for anything the path split cannot express. Two rules keep you out of trouble: - If the left side involves an operator, a computed value, or a variable you want interpolated, **wrap it in parentheses** — inside them it is plain JavaScript and ordinary variables are in scope. - If the left side is a method call, write it as one; `match foo.bar() == 3` is a supported shape and does not need parentheses. ## Why interviewers ask this It separates a candidate who has written Karate from one who has read about it. The tell-tale wrong answers are "you put a matcher object from a Java assertion library on the left" (there are none — the expected value goes on the right as literal JSON) and "you need a step definition to expose `response`" (you do not — it is auto-bound). Being able to say *variable, named JsonPath, method call, or parenthesised JavaScript*, and that `$` is the response, is the whole answer. The follow-up usually probes the boundary. Karate picks the shape mostly from the **text of the step** — a trailing `()` is a call, a leading `(` is JavaScript — but the routing is not purely textual. For a dotted left side Karate evaluates the leading identifier *first* and then re-routes on what came back: if the value is neither a map nor a list it throws the variable-plus-path split away and evaluates the whole left side as JavaScript instead, the `driver.cookies` edge case named in Karate's own source. So `match foo.length == 3` applies the JsonPath `$.length` when `foo` holds JSON, and is a plain JavaScript property read when `foo` holds a string: the same characters, a different route, decided by the runtime type. It is also why the right-hand side is a different world: there the expected value is written as literal JSON or XML, with embedded expressions and fuzzy markers, and no path context is implied. Keeping the two sides straight — *select on the left, describe on the right* — is what makes a Karate assertion readable in one pass.

  • Where does the `$variable` short-cut actually matter, if it is optional on the left of `match`?
    On the right-hand side and in other expression positions. On the left, the JsonPath context is implied and Karate resolves `$cat.name` and `cat.name` identically. On the right there is no implied path context, so `match foo[*].a == $data[*].a` is the documented way to say "apply this JsonPath to the variable `data`" — as is the equivalent `get data[*].a`.
  • If the left side can also be JavaScript, when do you need the parentheses?
    When the expression is not a path or a call — an operator, a literal, a comparison, or anything that needs a variable interpolated. `match (a + b) == 3` and `match (1 == 2) == false` both need them. A plain path (`cat.name`) or a method call (`cat.name.toUpperCase()`) does not, and on the right, parenthesising a JSON literal forces it through the JavaScript engine rather than the lenient JSON parser — on the left Karate adds those parentheses for you.
  • What is bound for you after an HTTP call, besides `response`?
    `responseStatus` (the status code as an integer), `responseHeaders` (a map of lists), `responseTime` (milliseconds), `responseCookies` and `responseBytes`. You normally assert the code with the `status` keyword rather than reading `responseStatus`, but all of them are ordinary variables you can put on the left of a `match`.

saying these in an interview costs you the question

  • Says a Java matcher object belongs on the left
  • Thinks a step definition is needed to expose the response
  • Claims the leading dollar sign is mandatory on the left
  • Believes only a plain variable name is allowed there
  • Thinks the left side is always JavaScript, never a path
  • Confuses the dollar sign with a doc-string or placeholder