Skip to main content

ASSERTIONS

Match Keyword

The match keyword provides intelligent comparison for JSON, XML, and text with flexible validation patterns and data manipulation. It handles whitespace and key ordering automatically, producing clear error messages when assertions fail.

On this page:

Basic Match Operations

Simple JSON Matching

Compare JSON objects with exact equality. Key order and whitespace don't matter:

Gherkin
Feature: Simple JSON matching

Scenario: Simple JSON match
* def user = { id: 123, name: 'John Doe' }

# Exact match - order doesn't matter
* match user == { id: 123, name: 'John Doe' }
* match user == { name: 'John Doe', id: 123 }

# Property-specific matching
* match user.id == 123
* match user.name == 'John Doe'

Matching API Responses

Apply match to HTTP response validation:

Gherkin
Feature: API response matching

Scenario: Validate API response
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', 1
When method get
Then status 200

# Match specific fields
* match response.id == 1
* match response.name == 'Leanne Graham'
* match response.email == 'Sincere@april.biz'

Match with Variables

Variables work on both sides of match expressions:

Gherkin
Feature: Match with variables

Scenario: Match with variables
* def expected = { id: 123, name: 'John Doe' }
* def actual = { name: 'John Doe', id: 123 }

# Variables can be compared
* match actual == expected

* def expectedId = 123
* match actual.id == expectedId
Left-Hand Side Rules

The left-hand side of match must be:

  • A variable name: foo
  • A named JsonPath/XPath: foo.bar or foo[0].name
  • A function call: foo.bar() or karate.get('key')
  • An expression in parentheses: (foo + bar)

match != (Not Equals)

Use for simple negative assertions:

Gherkin
Feature: Not equals matching

Scenario: Not equals validation
* def user = { id: 123, status: 'active' }

# Negative assertions
* match user != { id: 456 }
* match user.status != 'inactive'
* match user.id != 0

# Text not equals
* def message = 'Success'
* match message != 'Error'
* match message != ''
tip

Prefer match == with fuzzy markers (#notnull, #notpresent) over != for complex validations. Use != for simple string or number comparisons.

Match Contains

JSON Object Contains

Check for subset matching without requiring exact equality:

Gherkin
Feature: Object contains matching

Scenario: Object contains
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', 1
When method get
Then status 200

# Only check specific fields exist with expected values
* match response contains { id: 1, username: 'Bret' }
* match response contains { email: 'Sincere@april.biz' }

Array Contains

Check if arrays contain specific elements:

Gherkin
Feature: Array contains matching

Scenario: Array contains
* def tags = ['admin', 'verified', 'premium']

# Single element
* match tags contains 'admin'

# Multiple elements (order doesn't matter)
* match tags contains ['admin', 'verified']
* match tags contains ['verified', 'admin']

Not Contains (!contains)

Verify elements are absent:

Gherkin
Feature: Not contains matching

Scenario: Negative contains
* def user = { id: 123, name: 'John' }

# Verify keys don't have certain values
* match user !contains { id: 456 }
* match user !contains { deleted: true }

# Array not contains
* def tags = ['admin', 'verified']
* match tags !contains 'suspended'
* match tags !contains [4, 5]

contains only

Assert all elements are present in any order:

Gherkin
Feature: Contains only matching

Scenario: Contains only - exact elements, any order
* def numbers = [1, 2, 3]

# All elements present, order doesn't matter
* match numbers contains only [3, 2, 1]
* match numbers contains only [2, 3, 1]

# This would fail - missing element 3
# * match numbers contains only [1, 2]

contains any

Assert at least one element is present:

Gherkin
Feature: Contains any matching

Scenario: Contains any - at least one element
* def tags = ['admin', 'verified', 'premium']

# At least one must be present
* match tags contains any ['admin', 'superuser']
* match tags contains any ['enterprise', 'premium']

# Works for objects too
* def data = { a: 1, b: 'x' }
* match data contains any { b: 'x', c: true }

contains deep

Recursive matching for nested structures:

Gherkin
Feature: Contains deep matching

Scenario: Contains deep - recursive matching
* def original = { a: 1, b: 2, c: 3, d: { a: 1, b: 2 } }
* def expected = { a: 1, c: 3, d: { b: 2 } }

# Deep nested matching - only checks specified keys
* match original contains deep expected

Scenario: Contains deep with arrays
* def original = { a: 1, arr: [ { b: 2, c: 3 }, { b: 3, c: 4 } ] }
* def expected = { a: 1, arr: [ { b: 2 }, { c: 4 } ] }

* match original contains deep expected

contains only deep

Like match == but array order doesn't matter at any depth:

Gherkin
Feature: Contains only deep matching

Scenario: Contains only deep
* def response = { foo: [ 'a', 'b', 'c' ] }

# Order doesn't matter at any depth
* match response contains only deep { foo: [ 'c', 'a', 'b' ] }

Match Each

Validate Array Elements

Apply validation to every element in an array:

Gherkin
Feature: Match each validation

Scenario: Validate each array element
Given url 'https://jsonplaceholder.typicode.com'
And path 'users'
When method get
Then status 200

# Each user must have these fields with correct types
* match each response == { id: '#number', name: '#string', email: '#string', username: '#string', phone: '#string', website: '#string', address: '#object', company: '#object' }

# Each element contains subset
* match each response contains { id: '#number', email: '#string' }

Cross-Field Validation

Use _$ to reference the parent object in each iteration:

Gherkin
Feature: Cross-field validation

Scenario: Parent reference with _$
* def orders =
"""
[
{ "items": [{ "price": 100 }, { "price": 200 }], "total": 300 },
{ "items": [{ "price": 50 }], "total": 50 }
]
"""

# Validate total equals sum of item prices
* match each orders contains { total: '#? _ == _$.items.reduce((s, i) => s + i.price, 0)' }

match each contains deep

Combine match each with contains deep for nested validation:

Gherkin
Feature: Match each contains deep

Scenario: Each contains deep
* def response =
"""
[
{ "a": 1, "arr": [ { "b": 2, "c": 3 } ] },
{ "a": 1, "arr": [ { "b": 2, "c": 3 }, { "b": 4, "c": 5 } ] }
]
"""

# Each item must deeply contain the expected structure
* match each response contains deep { a: 1, arr: [ { b: 2 } ] }

Symbol Reference

SymbolEvaluates To
_Current value (self)
$JSON root of the document
_$Parent object in match each

Fuzzy Matching

Type Validation Markers

Validate data types without checking exact values:

Gherkin
Feature: Type validation

Scenario: Type validation markers
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', 1
When method get
Then status 200

# Type-based validation
* match response ==
"""
{
id: '#number',
name: '#string',
username: '#string',
email: '#string',
address: '#object',
phone: '#string',
website: '#string',
company: '#object'
}
"""

Complete Marker Reference

MarkerDescription
#ignoreSkip validation for this field
#nullMust be null (key must exist)
#notnullMust not be null
#presentKey must exist (any value, even null)
#notpresentKey must not exist
#stringMust be a string
#numberMust be a number
#booleanMust be boolean (true/false)
#arrayMust be a JSON array
#objectMust be a JSON object
#uuidMust match UUID format
#regex STRMust match regex pattern
#? EXPRJavaScript expression must return true
#[NUM]Array must have NUM elements
#[] EXPRArray validation with optional schema
#(EXPR)Embedded expression (substituted before match)
Regex Escaping

Regex patterns need double backslash escaping: #regex a\\.dot matches a.dot

Optional Fields (##)

Use ## prefix to mark fields as optional or nullable:

Gherkin
Feature: Optional field validation

Scenario: Optional field validation
* def user = { name: 'John', role: 'admin' }

# Optional fields - can be missing or null
* match user == { name: '#string', role: '#string', email: '##string', phone: '##string' }

Scenario: Optional null handling
# ##null matches both missing keys AND keys with null values
* def foo = { a: 1 }
* match foo == { a: 1, b: '##null' }

* def bar = { a: 1, b: null }
* match bar == { a: 1, b: '##null' }

#null vs #notpresent

Karate distinguishes between null values and missing keys:

Gherkin
Feature: Null vs not present

Scenario: Null vs not present
# Key missing entirely
* def foo = { }
* match foo == { a: '##null' }
* match foo == { a: '#notpresent' }

# Key exists with null value
* def bar = { a: null }
* match bar == { a: '#null' }
* match bar == { a: '#present' }

# Key exists with value
* def baz = { a: 1 }
* match baz == { a: '#notnull' }
* match baz == { a: '#present' }

Custom Validation with #?

Write custom validation logic using JavaScript expressions:

Gherkin
Feature: Custom validation

Scenario: Self-validation expressions
* def product = { price: 99, discount: 15, quantity: 5 }

# Custom validation using #? and _ (self)
* match product == { price: '#number? _ > 0 && _ < 10000', discount: '#number? _ >= 0 && _ <= 100', quantity: '#number? _ > 0' }

Scenario: Validation with external variables
* def min = 1
* def max = 100
* def value = { count: 50 }

* match value == { count: '#? _ >= min && _ <= max' }

Scenario: Custom validation functions
* def isValidEmail = function(e) { return e.indexOf('@') > 0 }
* def user = { email: 'john@example.com' }

* match user.email == '#? isValidEmail(_)'

Cross-Field Validation with $

Reference the JSON root using $ for cross-field validation:

Gherkin
Feature: Cross-field validation

Scenario: Cross-field validation
* def temperature = { celsius: 100, fahrenheit: 212 }

# Validate fahrenheit based on celsius value
* match temperature == { celsius: '#number', fahrenheit: '#? _ == $.celsius * 1.8 + 32' }

# Using embedded expression (cleaner for equality checks)
* match temperature contains { fahrenheit: '#($.celsius * 1.8 + 32)' }

Array Length Validation

Use #[NUM] shortcut for array size validation:

Gherkin
Feature: Array length validation

Scenario: Array length validation
* def items = ['a', 'b', 'c']

# Check array type
* match items == '#[]'

# Check exact length
* match items == '#[3]'

# Check length with element schema
* match items == '#[3] #string'

# Validate each element with predicate
* match items == '#[]? _.length == 1'

Data Manipulation

set - Add or Modify Properties

Modify JSON objects by setting properties:

Gherkin
Feature: Set properties

Scenario: Set properties on JSON
* def user = { id: 123, name: 'John' }

# Add new properties
* set user.active = true
* set user.role = 'admin'

# Create nested properties (auto-creates path)
* set user.profile.email = 'john@example.com'
* set user.profile.verified = true

# Verify changes
* match user.active == true
* match user.profile.email == 'john@example.com'

set multiple - Bulk Assignment

Use tables to set multiple properties at once:

Gherkin
Feature: Bulk property assignment

Scenario: Bulk property assignment
* def user = {}

# Table-based assignment
* set user
| path | value |
| name.first | 'John' |
| name.last | 'Doe' |
| age | 30 |
| profile.email | 'john@example.com' |

# Verify bulk assignment
* match user == { name: { first: 'John', last: 'Doe' }, age: 30, profile: { email: 'john@example.com' } }

Create arrays with multiple columns:

Gherkin
Feature: Create array with set

Scenario: Create array with set
* set users
| path | 0 | 1 |
| name | 'John' | 'Jane' |
| role | 'admin' | 'user' |

* match users == [{ name: 'John', role: 'admin' }, { name: 'Jane', role: 'user' }]

remove - Delete Properties

Remove keys from JSON or XML:

Gherkin
Feature: Remove properties

Scenario: Remove JSON properties
* def user = { id: 123, name: 'John', password: 'secret', temp: 'data' }

# Remove single property
* remove user.password

# Remove using JsonPath
* remove user $.temp

# Verify removal
* match user == { id: 123, name: 'John' }
* match user.password == '#notpresent'

Remove array elements by index:

Gherkin
Feature: Remove array elements

Scenario: Remove array elements
* def items = [1, 2, 3, 4, 5]

# Remove by index
* remove items[1]
* match items == [1, 3, 4, 5]

# Remove using JsonPath
* remove items $[0]
* match items == [3, 4, 5]

remove - XML Elements

Remove works for XML as well:

Gherkin
Feature: Remove XML elements

Scenario: Remove XML elements
* def xml = <root><item>keep</item><temp>remove</temp></root>

# Remove XML element
* remove xml /root/temp
* match xml == <root><item>keep</item></root>

delete - Dynamic Property Removal

Use delete for dynamic paths with variable keys:

Gherkin
Feature: Dynamic property removal

Scenario: Dynamic property removal
* def key = 'tempData'
* def user = { id: 123, tempData: 'remove-me' }

# Delete using variable key
* delete user[key]

# Verify removal
* match user == { id: 123 }

JsonPath Queries

Wildcards and Filters

Extract data using JsonPath expressions:

Gherkin
Feature: JsonPath wildcards

Scenario: JsonPath with wildcards
* def cat =
"""
{
"name": "Billie",
"kittens": [
{ "id": 23, "name": "Bob" },
{ "id": 42, "name": "Wild" }
]
}
"""

# Wildcard returns arrays
* match cat.kittens[*].id == [23, 42]
* match cat.kittens[*].name == ['Bob', 'Wild']

# Deep scan with .. operator (matches at any depth)
* match cat..name == ['Billie', 'Bob', 'Wild']

# JsonPath filter
* def bob = get[0] cat.kittens[?(@.id==23)]
* match bob.name == 'Bob'

get Keyword

Extract values using the get keyword:

Gherkin
Feature: Get keyword

Scenario: Extract with get
* def cat =
"""
{
"name": "Billie",
"kittens": [
{ "id": 23, "name": "Bob" },
{ "id": 42, "name": "Wild" }
]
}
"""

# Get array of names
* def names = get cat.kittens[*].name
* match names == ['Bob', 'Wild']

# Get first matching element
* def firstKitten = get[0] cat.kittens
* match firstKitten.id == 23

JsonPath on Variables

Use $varName for JsonPath on variables other than response:

Gherkin
Feature: JsonPath on variables

Scenario: JsonPath on variables
* def data = { users: [{ name: 'John' }, { name: 'Jane' }] }

# Short-cut form for variables
* def names = $data.users[*].name
* match names == ['John', 'Jane']

# Equivalent long form
* def names2 = get data.users[*].name
* match names2 == ['John', 'Jane']
$ Shortcut for response

In JsonPath expressions, bare $ is a shortcut for the response variable only. For other variables, use $varName.path form.

XML Matching

All fuzzy markers work with XML:

Gherkin
Feature: XML matching

Scenario: XML fuzzy matching
* def xml = <root><hello>world</hello><id>123</id></root>

# Fuzzy markers in XML
* match xml == <root><hello>#string</hello><id>#ignore</id></root>

Scenario: XML attribute matching
* def xml = <root><item id="123" status="active">content</item></root>

# Match with attribute validation
* match xml == <root><item id="#string" status="#ignore">content</item></root>

Text and Binary Matching

Match non-JSON responses:

Gherkin
Feature: Text and binary matching

Scenario: Text matching
* def message = 'Health Check OK'

* match message == 'Health Check OK'
* match message contains 'OK'
* match message !contains 'Error'

match header

Shortcut for response header validation (case-insensitive):

Gherkin
Feature: Header matching

Scenario: Header matching
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', 1
When method get
Then status 200

# Case-insensitive header matching
* match header Content-Type contains 'application/json'

Next Steps