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.