Q13 of 40 · Karate
Explain how `* match each` works for validating arrays of objects.
KarateMidkaratematch-eacharraysassertionsapi-testing
Short answer
Short answer: * match each arrayVariable == pattern asserts that every element of the array satisfies the pattern. The pattern can use any # wildcard markers. It replaces a loop and individual element assertions with one readable line — * match each response.users == { id: '#number', name: '#string' } validates every user in the list.
Detail
match each applies the same pattern assertion to every element of an array:
# Assert every order has a numeric ID and a string status
* match each response.orders == { id: '#number', status: '#string' }
# More specific — every active user has required fields
* match each response.users == {
id: '#uuid',
name: '#string',
email: '#regex .+@.+',
active: true
}
Combining with a filter (via embedded JS):
# Only validate active users
* def activeUsers = response.users.filter(u => u.active)
* match each activeUsers == { id: '#uuid', role: 'ACTIVE_USER' }
match each with a contains check:
* match each response.items contains { price: '#number' }
# Every item has at least a numeric price (extra fields allowed)
Comparison to REST Assured:
- REST Assured:
.body("items.price", everyItem(greaterThan(0)))— checks one field across all items - Karate:
match each response.items == { price: '#? _ > 0', sku: '#string' }— validates the whole element structure
Karate's approach is more expressive for validating the full structure of each array element.
// EXAMPLE
list-validation.feature
Feature: Validate list responses
Scenario: Product list has correct structure for every item
* url 'https://api.example.com'
Given path '/products'
And params { category: 'electronics', inStock: true }
When method GET
Then status 200
# Every product in the list must match this pattern
* match each response.content == {
id: '#uuid',
name: '#string',
price: '#? _ > 0',
inStock: true,
category: 'electronics'
}
# Array size check (separate assertion)
* match response.content.length == '#? _ > 0'
# Negation — no product has a null SKU
* def skus = response.content.map(p => p.sku)
* match each skus == '#notnull'// WHAT INTERVIEWERS LOOK FOR
Correct syntax (match each arrayName == pattern), using # wildcards within the pattern, and combining with contains for partial element matching. Comparing to REST Assured's everyItem() matcher shows breadth.
// COMMON PITFALL
Writing a for-each loop in embedded JavaScript to check each element individually — match each does this in one line. Candidates who haven't used match each often rediscover loops when the DSL already handles it.