Karate Framework

49Karate Framework

What you will master here

  • Why Karate exists — declarative API testing with no Java code per test
  • Gherkin-on-steroids DSL
  • Data-driven and chained scenarios
  • Matching: match, JSONPath, schema
  • Karate Gatling for performance testing
  • Karate UI (web automation) and Karate Mock
  • When to pick Karate vs REST Assured vs Postman vs Playwright request

49.1 What Karate is

Karate is a JVM-based, BDD-style API testing tool from Intuit. It removes Java boilerplate — tests are written in a Gherkin-derived DSL inside .feature files. No step-definition code; built-in matchers, JSON traversal, schema validation, JS expressions.

49.2 First test

Feature: users API

Background:
  * url 'https://api.example.com'
  * header Accept = 'application/json'

Scenario: create user
  Given path '/users'
  And request { name: 'Alice', email: 'alice@test.com' }
  When method post
  Then status 201
  And match response == { id: '#string', name: 'Alice', email: 'alice@test.com', createdAt: '#string' }
  And match response.id != null
  * def userId = response.id

Scenario: get the user just created
  Given path '/users', userId
  When method get
  Then status 200
  And match response.email == 'alice@test.com'

49.3 The match operator (Karate's killer feature)

* def actual = { foo: 'bar', baz: 42 }

* match actual == { foo: 'bar', baz: 42 }              # full equality
* match actual contains { foo: 'bar' }                 # partial
* match actual.baz == 42
* match actual.baz == '#number'                        # type
* match actual.foo == '#regex [a-z]+'                  # regex
* match actual contains only { foo: 'bar', baz: 42 }   # exact set

# Arrays
* def list = [{ id: 1 }, { id: 2 }, { id: 3 }]
* match list[*].id == [1, 2, 3]                        # extract
* match each list == { id: '#number' }                 # every element
* match list[?(@.id == 2)] != []                       # JSONPath filter

49.4 Data-driven via Examples

Scenario Outline: status code <code> for <path>
  Given path '<path>'
  When method get
  Then status <code>

  Examples:
    | path        | code |
    | /health     | 200  |
    | /users/9999 | 404  |
    | /admin      | 403  |

49.5 Chained scenarios — calling features from features

* def created = call read('create-user.feature') { email: 'qa@test.com' }
* def userId = created.userId

Given path '/users', userId
When method get
Then status 200

49.6 Parallel runner

// JUnit 5 wrapper
public class AllTests {
  @Test
  public void runAll() {
    Results results = Runner.path("classpath:tests")
        .tags("@regression")
        .parallel(8);
    assertEquals(0, results.getFailCount(), results.getErrorMessages());
  }
}

49.7 Karate UI + Mock

49.8 When to pick Karate

Pick Karate whenPick alternative when
Team mixes engineers + non-engineers writing testsEveryone is a developer (REST Assured or Playwright fits better)
You want one tool for API + perf + simple UIYou need deep UI (use Playwright)
Schema/structural assertions dominateYou need full type-safe TS / Java
You want zero step-definition codeYou want code review on imperative tests

Module 47 — Karate Q&A

What's Karate's "match" operator do?
Built-in structural comparison: equality, contains, contains only, type markers (#string, #number, #boolean), regex, JSONPath filters. Replaces a stack of Hamcrest matchers or hand-written assertions.
Karate vs REST Assured?
REST Assured is a Java DSL — you write Java test methods and chain BDD-style assertions. Karate is a feature-file DSL — no Java for the test, but you can call Java helpers when needed. Karate is more accessible to non-engineers; REST Assured fits engineer-only teams better.
How does data-driven testing work in Karate?
Scenario Outline + Examples table — same as Cucumber. Karate also supports call-with-array for fully programmatic data-driven runs.
How do you chain scenarios?
call read('other.feature') {arg: 'value'} calls another feature and returns its results as a context object. Used to share setup (create user, login) across feature files.
Can Karate do load testing?
Yes — Karate Gatling reuses your feature files as Gatling scenarios. One source of truth for functional + load.
What's the parallel runner?
Built-in JUnit-driven parallel executor: Runner.path(...).parallel(N) runs feature files across N threads. No external Maven Surefire fork config needed.

Karate Complete Feature File — REST API Testing

Feature: User Management API

  Background:
    * url 'https://api.example.com'
    * header Authorization = 'Bearer ' + karate.get('authToken')
    * def baseUrl = 'https://api.example.com'

  Scenario: Create user and verify response
    Given path '/users'
    And request { name: 'John Doe', email: 'john@example.com', role: 'admin' }
    When method POST
    Then status 201
    And match response == { id: '#notnull', name: 'John Doe', email: 'john@example.com', createdAt: '#present' }
    And match responseHeaders['Content-Type'][0] contains 'application/json'
    * def userId = response.id

  Scenario Outline: Get user by ID
    Given path '/users/' + <userId>
    When method GET
    Then status <status>
    And match response.name == <name>

    Examples:
      | userId | status | name          |
      | 1      | 200    | 'Alice'       |
      | 9999   | 404    | '#notpresent' |

  Scenario: Update user with partial data (PATCH)
    Given path '/users/1'
    And request { name: 'Alice Updated' }
    When method PATCH
    Then status 200
    And match response.name == 'Alice Updated'
    And match response.updatedAt != response.createdAt

  Scenario: Validate paginated list response
    Given path '/users'
    And param page = 1
    And param limit = 10
    When method GET
    Then status 200
    And match response ==
      """
      {
        data: '#[] #object',
        total: '#number',
        page: 1,
        limit: 10,
        hasNext: '#boolean'
      }
      """
    And match each response.data == { id: '#number', name: '#string', email: '#regex .+@.+' }

Karate Auth & Reusable Helpers

# auth.feature — called from other features
Feature: Authentication Helper

  Scenario: Get auth token
    Given url 'https://api.example.com/auth/login'
    And request { username: '#(username)', password: '#(password)' }
    When method POST
    Then status 200
    * def authToken = response.token

---
# main.feature — reuse auth
Feature: Main API Tests

  Background:
    * def auth = call read('classpath:auth.feature') { username: 'admin', password: 'secret' }
    * def authToken = auth.authToken
    * url 'https://api.example.com'
    * header Authorization = 'Bearer ' + authToken

Karate JavaScript Inline Functions

Feature: Advanced Karate Patterns

  Scenario: Generate dynamic test data with JS
    * def uuid = function(){ return java.util.UUID.randomUUID() + '' }
    * def email = function(name){ return name.toLowerCase() + '@test.com' }
    * def timestamp = function(){ return new Date().toISOString() }

    * def user = { id: '#(uuid())', name: 'Test User', email: '#(email("TestUser"))' }
    Given path '/users'
    And request user
    When method POST
    Then status 201

  Scenario: Schema validation with match each
    Given path '/products'
    When method GET
    Then status 200
    # Every item in array must match schema
    And match each response.items ==
      """
      {
        id: '#number',
        name: '#string',
        price: '#? _ > 0',
        category: '#regex ^(electronics|clothing|food)$',
        inStock: '#boolean',
        tags: '##[] #string'
      }
      """

  Scenario: Test file upload
    Given path '/uploads'
    And multipart file file = { read: 'classpath:test-image.jpg', filename: 'image.jpg', contentType: 'image/jpeg' }
    And multipart field description = 'Test upload'
    When method POST
    Then status 200
    And match response.url contains 'https://storage.'

Karate Config & Parallel Execution

// karate-config.js
function fn() {
  var env = karate.env || 'dev';
  var config = {
    env: env,
    apiTimeout: 5000
  };

  if (env === 'dev') {
    config.baseUrl = 'http://localhost:8080';
    config.apiKey = 'dev-key-123';
  } else if (env === 'staging') {
    config.baseUrl = 'https://staging.api.example.com';
    config.apiKey = karate.properties['staging.api.key'];
  } else if (env === 'prod') {
    config.baseUrl = 'https://api.example.com';
    config.apiKey = karate.properties['prod.api.key'];
  }

  // Global setup: get auth token once for all tests
  var login = karate.callSingle('classpath:auth.feature', { username: 'admin', password: 'secret' });
  config.authToken = login.authToken;

  return config;
}
// KarateRunner.java — parallel execution
import com.intuit.karate.junit5.Karate;
import org.junit.jupiter.api.Test;
import com.intuit.karate.Results;
import com.intuit.karate.Runner;
import static org.junit.jupiter.api.Assertions.*;

class KarateRunner {

    @Test
    void testParallel() {
        Results results = Runner.path("classpath:features")
            .outputHtmlReport(true)
            .outputJunitXml(true)
            .parallel(5);  // 5 threads

        assertEquals(0, results.getFailCount(),
            results.getErrorMessages());
    }
}