Skip to main content

FAQ

Frequently Asked Questions

Get quick answers to common questions about Karate installation, configuration, testing strategies, and troubleshooting.

Getting Started

What is Karate?

Karate is an open-source tool that combines API test automation, mocks, performance testing, and UI automation into a single unified framework. Tests are written in plain text using Gherkin syntax, making them readable by technical and non-technical team members.

Do I need programming knowledge to use Karate?

No. Karate tests use plain text with simple, readable syntax. Programming knowledge helps with advanced features like custom JavaScript functions and Java interop, but is not required for basic API testing.

Feature: Basic API test

Scenario: Get user information
Given url 'https://api.example.com'
And path 'users', 123
When method GET
Then status 200
And match response.name == 'John Doe'

How does Karate compare to other testing tools?

Karate offers a unified framework for API, UI, performance testing, and mocks. Unlike Cucumber, it requires no step definitions or glue code. Compared to Rest Assured, Karate provides simpler syntax with built-in assertions and debugging.

When to use Karate:

  • Testing APIs and UIs together
  • Teams with mixed technical skills
  • Need built-in mocking capabilities
  • Want unified test reporting

Consider alternatives:

  • Pure frontend testing: Use Cypress or Playwright
  • Java-heavy teams comfortable with code: Use Rest Assured
  • High-volume load testing: Use JMeter or k6
  • Mobile app testing: Use Appium directly

Installation & Setup

What Java version do I need?

Java 17 or higher is required as of Karate 1.4.0. Java 21 is recommended for best performance and modern JVM features.

# Check Java version
java -version
# Should show: java version "17.0.1" or higher

Version requirements:

  • Karate 0.9.x - 1.3.x: Java 8+
  • Karate 1.4.x+: Java 17+

Can I use Karate with Node.js projects?

Yes. Install Karate CLI via npm and integrate with your existing npm scripts and CI/CD pipelines.

# Global installation
npm install -g @karatelabs/karate-cli

# Run tests
karate test.feature
karate --threads 4 src/test/features

# Local installation
npm install --save-dev @karatelabs/karate-cli
package.json
{
"scripts": {
"test:api": "karate src/test/features",
"test:api:parallel": "karate --threads 4 src/test/features"
}
}

Project structure example:

my-node-project/
├── src/
│ └── app.js
├── test/
│ ├── unit/ # Jest/Mocha tests
│ └── api/ # Karate tests
│ ├── karate-config.js
│ └── features/
│ └── user-api.feature
└── karate-reports/

How do I fix Maven archetype issues behind a corporate proxy?

If Maven archetype commands fail behind a corporate proxy, temporarily disable your Maven settings.xml file or use the karate-core dependency with the all classifier.

pom.xml
<dependency>
<groupId>io.karatelabs</groupId>
<artifactId>karate-core</artifactId>
<version>${karate.version}</version>
<classifier>all</classifier>
<scope>test</scope>
</dependency>

Add this to your pom.xml to keep .feature files with test classes:

pom.xml
<build>
<testResources>
<testResource>
<directory>src/test/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
</build>

Gradle configuration:

build.gradle
sourceSets {
test {
resources {
srcDir file('src/test/java')
exclude '**/*.java'
}
}
}

Benefits:

  • Keep .feature files with test classes
  • Easier artifact management in one location
  • No switching between src/test/java and src/test/resources

For more details, visit the Quick Start guide.

How do I set up VS Code for Karate?

Install the official Karate extension from the VS Code marketplace. Open a .feature file to activate syntax highlighting, autocomplete, and debugging features.

Extension features:

  • Syntax highlighting for Gherkin
  • Run scenarios directly from editor
  • Step-through debugging
  • IntelliSense for Karate keywords

API Testing

How do I handle authentication in tests?

Use the Background section to authenticate once and reuse the token across scenarios.

Feature: Protected API endpoints

Background:
Given url 'https://api.example.com'
And path 'auth/login'
And request { username: 'user', password: 'pass' }
When method POST
Then status 200
* def authToken = response.token

Scenario: Access protected resource
Given path 'protected-resource'
And header Authorization = 'Bearer ' + authToken
When method GET
Then status 200

How do I authenticate with OAuth 2.0 Client Credentials?

Create a reusable token feature and call it once using karate.callSingle():

auth/get-token.feature
Feature: Get OAuth token

Scenario: Get access token
Given url authUrl
And path 'oauth/token'
And form field grant_type = 'client_credentials'
And form field client_id = clientId
And form field client_secret = clientSecret
When method POST
Then status 200
* def accessToken = response.access_token

Configure in karate-config.js to run once and cache:

karate-config.js
function fn() {
var config = {
authUrl: 'https://auth.example.com',
clientId: 'my-client',
clientSecret: 'my-secret'
};

// Get token once across all parallel tests
var auth = karate.callSingle('classpath:auth/get-token.feature', config);
config.accessToken = auth.accessToken;

return config;
}

Use in your feature files:

Background:
* header Authorization = 'Bearer ' + accessToken

How do I handle JWT token refresh?

Use karate.callSingle() with caching for tokens that expire:

karate-config.js
function fn() {
// Cache token for 10 minutes (adjust based on token expiry)
karate.configure('callSingleCache', { minutes: 10 });

var auth = karate.callSingle('classpath:auth/login.feature');

return {
baseUrl: 'https://api.example.com',
accessToken: auth.token
};
}

For longer test runs, implement refresh logic in JavaScript:

auth/token-manager.js
function fn() {
var token = karate.get('accessToken');
var expiry = karate.get('tokenExpiry');

if (!token || Date.now() > expiry) {
var result = karate.call('classpath:auth/login.feature');
token = result.token;
karate.set('accessToken', token);
karate.set('tokenExpiry', Date.now() + (9 * 60 * 1000)); // 9 minutes
}
return token;
}

How do I test GraphQL APIs?

Use the text keyword to define GraphQL queries and send them as POST requests to the GraphQL endpoint.

Scenario: Query user data
Given url 'https://api.example.com/graphql'
And text query =
"""
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
"""
And request { query: '#(query)', variables: { id: '123' } }
When method POST
Then status 200
And match response.data.user.name == '#string'

Can I test file uploads?

Yes. Karate supports multipart file uploads with the multipart keyword.

Scenario: Upload PDF file
Given url 'https://api.example.com/upload'
And multipart file myFile = { read: 'test-file.pdf', filename: 'test.pdf', contentType: 'application/pdf' }
And multipart field message = 'Test upload'
When method POST
Then status 200

Data Management

How do I read test data from files?

Use the read function to load data from JSON, CSV, XML, or YAML files.

Scenario: Use external test data
* def userData = read('test-data/users.json')
* def user = userData[0]

# Read CSV data
* def csvData = read('test-data/users.csv')

Given url 'https://api.example.com'
And path 'users'
And request user
When method POST
Then status 201

Can I use databases in tests?

Yes. Access databases through Java interop or by calling HTTP endpoints that query your database.

Scenario: Query database via HTTP
Given url 'http://localhost:8080/db'
And path 'query'
And request { sql: 'SELECT * FROM users WHERE id = ?', params: [123] }
When method POST
Then status 200
* def dbResult = response.data[0]

How does Karate handle different data formats?

Karate natively supports JSON, XML, CSV, YAML, and binary data formats.

Scenario: Work with multiple formats
# JSON (native support)
* def user = { name: 'John', age: 30 }
* def users = read('users.json')

# XML (native support)
* def xmlData = <user><name>John</name></user>
* match xmlData/user/name == 'John'

# CSV (automatic conversion)
* def csvData = read('users.csv')
* def firstUser = csvData[0]

# YAML (automatic conversion)
* def config = read('config.yaml')

# Binary data
* def imageBytes = karate.readAsBytes('test-image.png')

Variables & Configuration

How do I use variables in karate-config.js?

Variables in karate-config.js must be returned in the config object to be available in feature files.

karate-config.js
function fn() {
var env = karate.env || 'dev';

var config = {
baseUrl: 'https://' + env + '.api.example.com',
timeout: 5000,
adminUser: 'admin@test.com',
apiVersion: 'v2'
};

// Environment-specific overrides
if (env === 'prod') {
config.baseUrl = 'https://api.example.com';
}

return config; // All properties become available as variables
}

Use these variables directly in your feature files:

Given url baseUrl
And path apiVersion, 'users'

How does variable scope work with def?

Variables defined with def are scoped to the current scenario. Use Background for shared setup across scenarios in the same feature.

Feature: Variable scope example

Background:
* def sharedVar = 'available in all scenarios'
* url baseUrl

Scenario: First test
* def localVar = 'only in this scenario'
* print sharedVar
* print localVar

Scenario: Second test
* print sharedVar
# localVar is not available here - defined in different scenario

For one-time setup across multiple features, use karate.callSingle() in karate-config.js:

karate-config.js
function fn() {
var auth = karate.callSingle('classpath:auth/login.feature');
return {
baseUrl: 'https://api.example.com',
authToken: auth.token
};
}

How do I set dynamic data in request bodies?

Use embedded expressions #() to insert variable values into JSON:

Scenario: Dynamic request body
* def userId = 123
* def timestamp = java.lang.System.currentTimeMillis()

# Method 1: Embedded expressions
Given request { id: '#(userId)', created: '#(timestamp)' }
When method POST
Then status 201

# Method 2: Build object in JavaScript
* def body = { id: userId, created: timestamp, name: 'Test' }
Given request body
When method POST
Then status 201

Test Execution

How do I run tests in parallel?

Use the JUnit 5 runner with the parallel method to specify thread count.

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

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

How do I skip tests conditionally?

Use the karate.abort function to skip tests based on environment or configuration.

Background:
* def skipTest = karate.env == 'production'
* karate.abort(skipTest)

Scenario: Development only test
Given path 'debug/endpoint'
When method GET
Then status 200

Can I generate test reports?

Yes. Karate automatically generates detailed HTML reports in the target/karate-reports/ directory with timeline views, detailed logs, and pass/fail statistics.

Report formats:

  • HTML (interactive reports)
  • JSON (machine-readable)
  • JUnit XML (CI/CD integration)

Performance & Mocking

Can I do performance testing?

Yes. Karate integrates with Gatling for performance testing through the performance hook API.

@Test
void performanceTest() {
PerfHook hook = new PerfHook("classpath:perf/load-test.js");
Results results = Runner.path("classpath:features/api")
.hook(hook)
.parallel(10);
}

How do I create mock services?

Use karate.start to start a mock server from a feature file.

Feature: Mock server

Background:
* def port = karate.start('user-mock.feature').port
* url 'http://localhost:' + port

Scenario: Mock returns user data
Given path 'users', 1
When method GET
Then status 200
And match response == { id: 1, name: 'John Doe' }

Troubleshooting

Common Errors

How do I fix NoClassDefFoundError with Maven Surefire?

This error occurs when Maven Surefire plugin version conflicts with JUnit 5 or Karate dependencies.

Solution: Update your pom.xml with compatible versions:

pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>

For dependency conflicts, use the all classifier which bundles all dependencies:

pom.xml
<dependency>
<groupId>io.karatelabs</groupId>
<artifactId>karate-core</artifactId>
<version>${karate.version}</version>
<classifier>all</classifier>
<scope>test</scope>
</dependency>

How do I fix "ReferenceError: variable is not defined"?

This GraalVM/Polyglot error means a variable used in your feature file was never declared or returned from configuration.

Common causes:

  1. Variable not returned from karate-config.js
  2. Typo in variable name (names are case-sensitive)
  3. Variable defined in a different scope

Solution: Ensure your karate-config.js returns all required variables:

karate-config.js
function fn() {
var config = {
baseUrl: 'https://api.example.com', // Must match exact name used in features
timeout: 5000
};
return config;
}

Use the exact variable name in your feature file:

Given url baseUrl    # Correct - matches config
Given url BaseURL # Wrong - case mismatch causes error

How do I fix "javascript evaluation failed" errors?

This occurs when Karate's JavaScript engine cannot parse your code.

Common causes:

  1. Syntax errors in JavaScript files
  2. Using ES6+ features not supported by GraalJS
  3. Missing return statement in functions

Solution: Ensure your JavaScript files use standard function syntax:

my-function.js
function fn(arg) {
// Your logic here
return result; // Must return a value
}

Avoid ES6 arrow functions in separate .js files:

// Don't use arrow functions in .js files
const fn = (arg) => arg * 2; // May fail

// Use standard function syntax instead
function fn(arg) {
return arg * 2;
}

How do I fix ClassNotFoundException in VS Code?

This occurs when VS Code cannot find your Java classes or Karate dependencies.

Solutions:

  1. Reload the window: Press Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows), type "Reload Window"

  2. Clean and rebuild:

mvn clean compile test-compile
  1. Check your project structure: Ensure .feature files are in the correct location:
src/test/java/
└── mypackage/
├── MyTest.java
└── my.feature
  1. Update the VS Code Karate extension to the latest version

How do I fix Nashorn null errors?

Nashorn was replaced by GraalJS in Karate 1.0+. This error indicates version incompatibility.

Solution: Upgrade to Karate 1.4+ and Java 17+:

pom.xml
<dependency>
<groupId>io.karatelabs</groupId>
<artifactId>karate-junit5</artifactId>
<version>1.5.0</version>
<scope>test</scope>
</dependency>

If you must use older Java versions, stay on the Karate 0.9.x series.

How do I fix "Access to host class is not allowed"?

GraalJS restricts access to Java classes by default for security. This error occurs when using incorrect syntax for Java interop.

Solution: Use the correct Java.type() syntax:

# Correct way to access Java classes
* def UUID = Java.type('java.util.UUID')
* def id = UUID.randomUUID() + ''

# For your own classes - must be on classpath with public methods
* def MyUtils = Java.type('com.mycompany.MyUtils')
* def result = MyUtils.doSomething()

How do I fix "RuntimeException: not found: features"?

The Karate runner cannot locate your feature files.

Solution: Check your runner class path configuration:

@Karate.Test
Karate testAll() {
return Karate.run()
.relativeTo(getClass()); // Looks for features relative to this class
}

Ensure your file structure matches:

src/test/java/
└── mypackage/
├── MyRunner.java # Runner class
└── features/
└── my.feature # Feature files

Or specify an explicit path:

return Karate.run("classpath:features").relativeTo(getClass());

My tests are failing intermittently

Common causes include timing issues, test data dependencies, and environment differences.

Solutions:

  1. Timing issues: Add waits or increase timeouts
Background:
* configure readTimeout = 30000
* retry until responseStatus == 200
  1. Test data dependencies: Use unique identifiers
Background:
* def uniqueId = java.util.UUID.randomUUID()
  1. Environment differences: Use proper configuration
// karate-config.js
if (env === 'ci') {
config.readTimeout = 60000;
}

How do I debug failing tests?

Enable detailed logging and response printing with configuration options.

Background:
* configure logPrettyResponse = true
* configure printEnabled = true

Scenario: Debug failing test
Given url 'https://api.example.com'
And path 'users', 1
When method GET
* print 'Response:', response
Then status 200

Tests work locally but fail in CI

Ensure CI uses the correct environment configuration and has adequate timeouts for slower environments.

# GitHub Actions example
- name: Run Tests
run: mvn test -Dkarate.env=ci

Common solutions:

  • Verify environment configuration matches CI
  • Increase timeouts for slower CI environments
  • Ensure all required services are running
  • Use test-specific data or mocks

Integration & Advanced

Can I integrate with Cucumber reports?

Yes. Karate generates Cucumber-compatible JSON reports.

Results results = Runner.path("classpath:features")
.outputCucumberJson(true)
.parallel(5);

How do I call Java code from Karate?

Use the Java.type function to access Java classes and call methods.

Scenario: Call Java utility
* def JavaUtils = Java.type('com.mycompany.JavaUtils')
* def result = JavaUtils.processData('input-data')
* match result == 'expected-output'

# Call static methods
* def uuid = java.util.UUID.randomUUID() + ''

Can I use custom assertions?

Yes. Create JavaScript functions in karate-config.js and use them in tests.

// karate-config.js
function customAssert(actual, expected) {
return actual.toLowerCase() === expected.toLowerCase();
}

return { customAssert: customAssert };
Scenario: Use custom assertion
* assert customAssert(response.name, 'JOHN DOE')

Community & Support

Where can I get support?

Free community support:

Enterprise support:

  • Professional services and architecture design
  • Priority support with SLA guarantees
  • Corporate training programs
  • Custom feature development

Is Karate suitable for enterprise use?

Yes. Karate is widely adopted by Fortune 500 companies and large enterprises for production environments with high transaction volumes.

Enterprise benefits:

  • Robust parallel execution and distributed testing
  • Comprehensive reporting for audit and compliance
  • Built-in support for OAuth, SAML, and mutual TLS
  • Reduces tool sprawl with unified API, UI, performance, and mock testing

How can I contribute to Karate?

Contribute through code improvements, documentation, community support, or testing beta releases.

Ways to contribute:

  • Submit pull requests with tests and clear descriptions
  • Fix documentation typos or add examples
  • Answer questions on Stack Overflow
  • Test beta releases and provide feedback

Best Practices

What are common anti-patterns to avoid?

Avoid heavy setup in Background, testing implementation details, hardcoding environment values, and creating overly complex tests.

Anti-pattern: Heavy setup in Background

# DON'T
Background:
* call read('create-100-users.feature')
* call read('setup-complex-data.feature')

Better approach: Use callonce

# DO
Background:
* def testData = callonce read('lightweight-setup.feature')

Anti-pattern: Hardcoded environment values

# DON'T
Given url 'https://prod-api.company.com'

Better approach: Use configuration

# DO
Given url baseUrl

When should I NOT use Karate?

Karate is not ideal for pure unit testing, frontend-only testing, non-HTTP protocols, or mobile app testing.

Better alternatives:

  • Unit tests: JUnit 5, TestNG, Jest
  • UI-only tests: Cypress, Playwright
  • Load testing: JMeter, k6, Artillery
  • Mobile testing: Appium, Detox, Espresso
Key Points
  • Keep tests focused with single responsibility
  • Use callonce for expensive setup operations
  • Test behavior, not implementation details
  • Configure environment-specific values in karate-config.js

Next Steps