skip to content

Match Targets

Before anything is compared the step has to reach the value: a path into the response, a named variable, or a node inside a document. Interviewers probe the path syntax hardest.

on this pageshow

explore

questions

9

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
open as a page

In a Karate feature file asserting on an XML response, which XPath shapes may sit on the left of a `match` step, and what does a leading `/` alone select?

level: juniorimportance: must knowfreq 62%

basics

~20 s

Any valid XPath sits directly on the left of a Karate match step - no extractor object, no Java code. A leading slash means the response, so match /cat/name == 'Billie' equals match response /cat/name == 'Billie'.

open as a page

In a Karate feature file `cat.kittens` holds two objects with ids 23 and 42. Why does `* match cat.kittens[*].id == 23` fail, and how do you assert on just the first id?

level: middleimportance: must knowfreq 70%

basics

~20 s

The wildcard makes the path indefinite, so the left side is the array [23, 42] and never the scalar 23. Match the array, or collapse it in a def or on the right of the match with get[0] cat.kittens[*].id, which returns the first element.

open as a page

In a Karate feature file, match //teacher[@department='science']/subject == ['math', 'physics'] passes. What does that same step produce when the science teacher has only one subject element, and why does comparing it to ['math'] then fail?

level: middleimportance: must knowfreq 46%

basics

~20 s

An XPath selecting several nodes comes back as a list, so you compare it to a JSON array. A single node is unwrapped, so with one subject the step yields the string 'math' and ['math'] fails with data types don't match.

open as a page

In a Karate feature file, what is the difference between `get cat.kittens[*].id`, the `$cat.kittens[*].id` short-cut, and `karate.jsonPath(cat, expression)` — and when do you need the last one?

level: middleimportance: should knowfreq 56%

basics

~20 s

get and the $ short-cut both apply a JsonPath, written as literal step text, to a named variable. karate.jsonPath takes the path as a string argument, so use it when the path is built at runtime.

open as a page

In a Karate feature file, why can the XPath written into a match step not contain a variable, and what does karate.xmlPath(xml, expression) give you instead?

level: middleimportance: should knowfreq 36%

basics

~20 s

A match step's path is read literally from the step text, so nothing is interpolated. karate.xmlPath takes the path as an ordinary JavaScript string, so you can build it by concatenation, assign the result, and assert on that.

open as a page

In a Karate feature file, what type of value does an XPath on the left of a match produce for a leaf element, for an element with children, for an attribute, and for count()?

level: middleimportance: should knowfreq 40%

basics

~20 s

A leaf element yields its text as a string, so numbers arrive quoted. An element with children yields an XML chunk compared against an XML literal. An attribute yields its value as a string. XPath count() yields a number.

open as a page

A Karate step reads `* def id = get[0] $.items[?(@.type == 'special')].id` and the `match` after it passes in CI, even though no item in the response has that type. What is Karate doing, and how do you stop a bad filter from passing silently?

level: seniorimportance: should knowfreq 44%

basics

~20 s

A filter that matches nothing yields an empty list, not an error, and get[N] hands it back untouched; a missing property degrades to #notpresent. A bad path produces a value, so the assertion can pass vacuously.

open as a page

A SOAP response is wrapped in namespace prefixes such as soapenv: and acc:. How do you write the XPath on the left of a Karate match step against it, and what happens to those prefixes on the right side?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Write the XPath with no prefixes at all. Karate parses XML namespace-unaware by default, so /Envelope/Body/getAccountByPhoneNumber reaches soapenv:Envelope and acc:getAccountByPhoneNumber. On the right side, prefixes and xmlns attributes are stripped from both documents before they are compared.

open as a page