Skip to main content

GET STARTED

What's New in Karate v2

Karate v2 is a complete ground-up rewrite with significant improvements across the board. Most existing v1 tests work with just a dependency update — see the Migration Guide.

Performance & Scalability​

Embedded JavaScript Engine​

Karate v2 replaces GraalJS with a fast, hand-rolled JavaScript engine (karate-js) with ES6+ support, purpose-built for Java interop and thread-safe concurrent execution.

  • No GraalVM dependency — works on any Java 21+ JVM
  • Significantly faster for the Karate use-case (see benchmarks)
  • Thread-safe by design for parallel test execution

Virtual Threads (Java 21+)​

Karate v2 requires Java 21+ and leverages virtual threads for massive parallelism with minimal overhead. This means you can run hundreds of scenarios in parallel without tuning thread pools.

@lock Tag — Surgical Parallel Safety​

The v1 @parallel=false tag was all-or-nothing: tagging a feature opted it out of parallel execution entirely, even when only one resource was actually contended. v2 replaces it with @lock, a fine-grained mutual-exclusion primitive that keeps the rest of your suite running in parallel.

@lock=database
Scenario: insert a user
# only one @lock=database scenario runs at a time
# unrelated scenarios continue in parallel

@lock=database
Scenario: delete a user
# waits for the @lock=database scenario above

@lock=*
Scenario: schema migration smoke
# exclusive — runs alone, nothing else in the suite is concurrent
  • @lock=<name> — named lock; only scenarios sharing the name serialize against each other. Two different lock names (e.g. @lock=db and @lock=cache) still run concurrently.
  • @lock=* — exclusive lock; the scenario runs alone with no other scenarios concurrent. Use sparingly — it stalls the whole worker pool.
  • Place @lock on a Feature: line to apply it to every scenario in that feature — a drop-in for v1's feature-level @parallel=false.

The result: virtual-thread parallelism stays maximally effective, and you only pay the serialization cost where it's actually needed. See Controlling Parallelism with @lock.

Migrating from v1

The v1 @parallel=false tag is no longer recognized in v2. Replace it with @lock=<name> (or @lock=*). See Migration from v1.

Assertions & Test Data​

match within​

Assert that a numeric value falls within a range:

* match response.temperature within { low: 36.0, high: 37.5 }
* match response.score !within { low: 0, high: 50 }

karate.faker.*​

Built-in test data generation — no external libraries needed:

* def name = karate.faker.firstName()
* def email = karate.faker.email()
* def id = karate.faker.randomInt()
* def phone = karate.faker.phone()

karate.expect() — Chai-style Assertions​

Familiar BDD-style assertions for teams migrating from Postman or Mocha:

karate.expect(response.name).to.equal('John')
karate.expect(response.age).to.be.above(18)
karate.expect(response).to.have.property('email')
karate.expect(response.tags).to.include('active')

karate.uuid()​

Generate random UUIDs:

* def id = karate.uuid()

Complete diffs for failed match​

A single match against a JSON (or XML) value now reports every mismatched path in one error — not just the first one it finds. Each diff lists the path, the actual value, and the expected value, with type annotations so type drift is obvious:

match failed: EQUALS
$ | not equal | match failed for names: [a, b] (MAP:MAP)
{"a":1,"b":2,"c":3}
{"a":9,"b":9,"c":3}

$.b | not equal (NUMBER:NUMBER)
2
9

$.a | not equal (NUMBER:NUMBER)
1
9

You fix all the mismatches in one iteration instead of re-running the test for each one. Particularly useful for deeply nested responses. Full reference: Complete Mismatch Diffs.

Soft Assertions​

The complement to the per-match diff above: continue execution after a match failure and aggregate failures across multiple steps in a scenario.

* configure continueOnStepFailure = true
* match response.name == 'wrong' # recorded but doesn't stop
* match response.age == 999 # also recorded
* configure continueOnStepFailure = false

Each individual match still emits its complete diff (above) — together you get full failure detail per step and full coverage across the scenario. Full behavior and surface-point rules: configure continueOnStepFailure.

Modern HTTP Client​

Apache HttpClient 5.6​

Upgraded to Apache HttpClient 5.6 with Brotli compression support and improved connection management.

Declarative Auth​

Centralized authentication configuration — no more writing custom karate-config.js headers functions for common auth patterns:

// Basic Auth
configure auth = { type: 'basic', username: 'user', password: 'pass' }

// Bearer Token
configure auth = { type: 'bearer', token: 'your-token' }

// OAuth2 Client Credentials (with automatic token refresh)
configure auth = {
type: 'oauth2',
tokenUrl: 'https://auth.example.com/token',
clientId: '...',
clientSecret: '...'
}

// OAuth2 Authorization Code (PKCE)
configure auth = {
type: 'oauth2',
flow: 'authorization_code',
authUrl: '...',
tokenUrl: '...',
clientId: '...'
}

// NTLM
configure auth = {
type: 'ntlm',
username: '...',
password: '...',
domain: '...',
workstation: '...'
}

Auth configuration is automatically inherited by called features, and OAuth2 tokens are refreshed automatically.

Mock Server Rewrite​

The mock server has been completely rewritten with the new JS engine and a Netty-based HTTP server for improved performance. See Test Doubles and Mocking for details.

  • JavaScript file handlers as an alternative to feature files
  • Non-blocking response delays via Netty scheduler
  • Built-in CORS support

Gatling Integration​

Re-implemented Gatling integration with a pure Java architecture. See Performance Testing for details.

  • Java-only DSL (no Scala required)
  • PerfHook integration for HTTP-level metrics
  • URI pattern matching for request grouping
  • Custom performance events for non-HTTP operations

Browser Automation​

CDP Driver Rewrite​

Complete reimplementation using Chrome DevTools Protocol directly — no WebDriver dependency needed for Chrome/Chromium/Edge.

Auto-wait​

Automatic waiting before element operations reduces flaky tests. No more manual waitFor() calls for most interactions.

Browser Pooling​

PooledDriverProvider automatically manages a pool of browser instances for parallel UI test execution:

Runner.path("features/")
.parallel(4); // pool of 4 drivers auto-created

Shadow DOM Support​

CSS and wildcard locators now work inside Shadow DOM elements.

Visual Regression (Image Comparison)​

Image comparison is a redesigned, improved API — now the karate-image extension. Establish baselines by name, catch regressions, and review differences in an interactive report lightbox (side-by-side, slider, blink, onion-skin). See Image Comparison.

See UI Testing for complete browser automation documentation.

Developer Experience​

Modern HTML Reports​

A completely revamped report: a Tailwind-based UI with dark mode, an at-a-glance summary chart, JSON syntax highlighting, interactive tag filtering, and a timeline view for parallel-execution analysis.

Karate v2 HTML summary report with summary chart and tag filtering

See Test Reports for the full tour.

JSON Lines event stream​

A karate-events.jsonl lifecycle event stream (SUITE/FEATURE/SCENARIO enter+exit), flushed per line so IDE test runners and dashboards can tail it in real time. FEATURE_EXIT carries the full FeatureResult.toJson(). See Test Reports.

Runner.path("features/")
.outputJsonLines(true)
.parallel(5);

Unified configure logging​

v1 spread logging across logPrettyRequest, logPrettyResponse, printEnabled, lowerCaseResponseHeaders, and a custom Java HttpLogModifier interface. v2 collapses all of it into a single declarative bucket — including HTTP-only redaction, with no Java class needed:

configure logging = {
report: 'debug', // threshold for HTML report capture
console: 'info', // threshold for console / SLF4J output
pretty: true, // pretty-print HTTP JSON bodies
mask: { // declarative redaction (replaces v1 HttpLogModifier)
headers: ['Authorization', 'Cookie'],
jsonPaths: ['$.password', '$..token'],
patterns: [{ regex: '\\bBearer [A-Za-z0-9._-]+\\b', replacement: 'Bearer ***' }],
enableForUri: function(uri) { return uri.indexOf('/health') < 0 }
}
}

Mid-test changes auto-restore at scenario end. The full v1 → v2 mapping is in the migration guide.

Friendly assertion failure labels​

A Gherkin comment immediately above a match or assert step is used as the failure label — no new syntax, just write what the assertion is checking:

* def response = { status: 'pending' }
# status must be active before checkout
* match response.status == 'active'

On failure the report shows status must be active before checkout above the diff. The comment closest to the step wins, so multiple comments are fine.

JUnit 6 Integration​

Streaming dynamic test generation via @TestFactory for better IDE integration:

<dependency>
<groupId>io.karatelabs</groupId>
<artifactId>karate-junit6</artifactId>
<version>2.1.3</version>
<scope>test</scope>
</dependency>

Unified Event System​

Single RunListener API for observing and controlling test execution — replaces the multiple hook interfaces in v1.

Unified Failure Hook — configure onStepFailure​

One hook for every kind of step failure — match, assert, HTTP error, driver error. The hook receives a single info object exposing the failed step, the error, and three callbacks:

  • info.embed(bytes, mime, name) attaches an artefact (screenshot, page HTML, log, JSON) directly to the failed step in the HTML report
  • info.proceed() converts this hard failure into a soft assertion (per-step override of continueOnStepFailure)
  • info.stop() converts a soft assertion into a hard stop (the inverse override)
# Soft-assert only match steps; stop hard on HTTP / driver failures
* configure onStepFailure =
"""
function(info) {
if (info.step.text && info.step.text.indexOf('match ') === 0) {
info.proceed()
}
}
"""

This covers v1's continueAfter keyword-list use case dynamically, replaces the missing Driver.onFailure Plugin from v1, and surfaces failures to the RunListener bus via a new ErrorRunEvent. Full reference: onStepFailure hook.

Auto-Screenshot on UI Failure​

When a step fails in a UI scenario, Karate now automatically captures a full-page PNG and embeds it on the failed step in the HTML report. Enabled by default (screenshotOnFailure: true on the driver config); disable per-scenario with configure driver = { screenshotOnFailure: false }. The capture is wired through the unified onStepFailure pipeline, so a dead browser can't escalate into a second failure — and you can layer additional diagnostics (page HTML, network HARs, console output) alongside the auto-screenshot via the same hook. Details: Auto-Screenshot on Failure.

karate.sysenv() and karate.sysprop()​

Two new helpers for reading the runtime environment, with a default-value overload that collapses the old karate.properties['FOO'] || 'default' idiom into a single call:

* def apiHost = karate.sysenv('API_HOST', 'localhost')
* def port = karate.sysprop('server.port', '8080')
  • karate.sysenv(name, [default]) — read an OS environment variable. Falls back to default when unset or empty (shell ${VAR:-default} semantics). Cleaner than reaching for java.lang.System.getenv(...) from inside a feature.
  • karate.sysprop(name, [default]) — read a JVM system property; preferred form over the karate.properties[name] lookup.

Extension SPI + karate-boot.js (experimental)​

A new suite-lifetime extension mechanism for observers and integrations that need to participate in the full run from SUITE_ENTER through SUITE_EXIT. Extensions are configured declaratively from a karate-boot.js file at the working-directory root — opt-in, so suites without that file run exactly as before with zero overhead.

// karate-boot.js — runs once per Suite, before SUITE_ENTER
const image = boot.ext('image');
image.baselineDir = 'baselines';
image.threshold = 0.5;

Image Comparison is the first extension to ship on this surface. See Extensions and karate-boot.js for the full surface.

More Improvements​

  • ANSI colors in console output, works even outside IDE
  • JavaScript debugging is now possible
  • Large JSON operations (e.g., contains) use disk when needed to avoid out-of-memory issues
  • cURL export for HTTP requests
  • karate-config.js and karate-base.js are auto-discovered from the working directory if not on the classpath — handy for ad-hoc CLI runs and scripted execution

V1 Compatibility​

Karate v2 includes backward compatibility shims that allow most v1 code to work with minimal changes. The com.intuit.karate package delegates to the v2 implementation.

See the Migration Guide for step-by-step upgrade instructions.

Commercial & Enterprise​

Karate Labs offers commercial tools that complement the open-source framework:

  • Karate Xplorer — Desktop IDE with Postman emulation and step-through debugging
  • Karate Agent — AI-powered browser testing via LLM agents
  • IDE Plugins — IntelliJ and VS Code extensions with debugging support
  • WebSocket Testing — Commercial module for async protocol testing

See Enterprise & Commercial for details, or visit karatelabs.io.