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=dband@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
@lockon aFeature: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.
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.
See UI Testing for complete browser automation documentation.
Developer Experience
Modern HTML Reports
Bootstrap 5.3 reports with dark mode, interactive tag filtering, and timeline view for parallel execution visualization.
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 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.0.0</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 reportinfo.proceed()converts this hard failure into a soft assertion (per-step override ofcontinueOnStepFailure)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 todefaultwhen unset or empty (shell${VAR:-default}semantics). Cleaner than reaching forjava.lang.System.getenv(...)from inside a feature.karate.sysprop(name, [default])— read a JVM system property; preferred form over thekarate.properties[name]lookup.
Plugin SPI + karate-boot.js (experimental)
A new suite-lifetime plugin mechanism for observers and integrations that need to participate in the full run from SUITE_ENTER through SUITE_EXIT. Plugins 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 agent = boot.plugin('agent');
agent.url = boot.sysenv('AGENT_URL', 'http://localhost:4444');
agent.mode = boot.env === 'ci' ? 'batch' : 'final';
The first plugin to ship using this surface is the Karate Agent wire integration. See Plugins 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.jsandkarate-base.jsare 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.