Skip to main content

ADVANCED

Hooks and Lifecycle

Control test initialization, cleanup, and resource management using Karate's lifecycle hooks without requiring Java code.

On this page:

Hook Types Overview

HookWhen It RunsScope
karate-config.jsBefore every ScenarioGlobal
BackgroundBefore every Scenario in FeatureFeature
callonce in BackgroundOnce per FeatureFeature
karate.callSingle()Once globally (thread-safe)Global
configure beforeScenarioBefore every Scenario (before Background)Scenario
configure afterScenarioAfter every Scenario (pass or fail)Scenario
configure afterFeatureAfter all Scenarios in FeatureFeature

Background Setup

Use Background to run setup before every scenario in a feature:

Gherkin
Feature: User API tests

Background:
* url 'https://jsonplaceholder.typicode.com'
* def authToken = 'Bearer abc123'
* header Authorization = authToken

Scenario: Get user
Given path 'users', 1
When method get
Then status 200

Scenario: Get all users
Given path 'users'
When method get
Then status 200
And match response == '#[10]'

The Background runs before each scenario, ensuring consistent setup.

One-Time Feature Setup

Use callonce to execute expensive operations once per feature:

Gherkin
Feature: API tests with authentication

Background:
# Runs once per feature, cached for all scenarios
* def authData = callonce read('classpath:auth/login.feature')
* def token = authData.token
* url 'https://jsonplaceholder.typicode.com'
* header Authorization = 'Bearer ' + token

Scenario: First test
Given path 'users'
When method get
Then status 200

Scenario: Second test
Given path 'posts'
When method get
Then status 200
callonce vs call
  • call executes every time it's encountered
  • callonce executes once and caches the result for all scenarios in the feature

Before Scenario Hook

Execute setup logic before each scenario. Because beforeScenario fires before the Background, it must be configured in karate-config.js to take effect — setting it inside Background is a no-op for the current scenario.

karate-config.js
function fn() {
karate.configure('beforeScenario', function() {
karate.log('Starting:', karate.scenario.name);
});
return {};
}

For mock servers, beforeScenario can be set in the mock's Background and runs per request — useful for per-request setup since a mock's Background only runs once at server init.

After Scenario Hook

Execute cleanup logic after each scenario. The hook runs on both pass and fail paths, so teardown always executes:

Gherkin
Feature: After scenario cleanup

Background:
* configure afterScenario =
"""
function() {
karate.log('Scenario completed:', karate.scenario.name);
if (karate.info.errorMessage) {
karate.log('FAILED:', karate.info.errorMessage);
}
}
"""

Scenario: Test user endpoint
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', 1
When method get
Then status 200

Available Properties in Hooks

Access scenario information within hooks:

PropertyDescription
karate.scenario.nameCurrent scenario name
karate.info.errorMessageError message if scenario failed (null if passed)
karate.info.scenarioTypeType: Scenario or Scenario Outline

Hook Failures

A hook exception fails the enclosing scenario — the same convention that applies to regular steps. This surfaces bugs in teardown code that would otherwise be silently logged. Wrap the hook body in try/catch to suppress:

Gherkin
Background:
* configure afterScenario =
"""
function() {
try {
karate.call('classpath:cleanup.feature');
} catch (e) {
karate.log('cleanup failed (suppressed):', e);
}
}
"""

For beforeScenario, a hook failure halts the scenario by default. Set continueOnStepFailure if you want scenario steps to run even after a failed beforeScenario. For mock servers, a hook failure (either beforeScenario or afterScenario) surfaces as an HTTP 500 response with the error in the body.

After Feature Hook

Configure feature-level cleanup after all scenarios complete:

Gherkin
Feature: After feature cleanup

Background:
* configure afterFeature =
"""
function() {
karate.log('All scenarios in feature completed');
}
"""

Scenario: First scenario
* def result = 1 + 1
* match result == 2

Scenario: Second scenario
* def result = 2 + 2
* match result == 4
afterFeature Requirements

The afterFeature hook only works with the Runner API for parallel execution, not the JUnit runner.

// Required for afterFeature hooks to work
SuiteResult results = Runner.path("classpath:features").parallel(5);

After Scenario Outline Hook

Handle cleanup after all rows of a data-driven test complete:

Gherkin
Feature: Scenario Outline hooks

Background:
* configure afterScenario =
"""
function() {
karate.log('Row completed');
}
"""
* configure afterScenarioOutline =
"""
function() {
karate.log('All rows completed');
}
"""

Scenario Outline: Validate users
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', <id>
When method get
Then status 200

Examples:
| id |
| 1 |
| 2 |
| 3 |
  • afterScenario runs after each Examples row
  • afterScenarioOutline runs once after all rows complete

Configuration File

karate-config.js

Configure global settings in karate-config.js (processed before every scenario):

karate-config.js
function fn() {
var env = karate.env || 'dev';
karate.log('Running in environment:', env);

var config = {
baseUrl: 'https://jsonplaceholder.typicode.com'
};

if (env === 'prod') {
config.baseUrl = 'https://api.production.com';
}

// Set timeouts globally
karate.configure('connectTimeout', 5000);
karate.configure('readTimeout', 5000);

return config;
}

Variables returned in config are available to all scenarios.

Environment-Specific Config

Create karate-config-<env>.js files to override settings per environment:

karate-config-dev.js
function fn() {
return {
baseUrl: 'http://localhost:8080',
debugMode: true
};
}

Run with: -Dkarate.env=dev

Global One-Time Setup

Use karate.callSingle() for initialization that runs once globally, even across parallel threads:

karate-config.js
function fn() {
var config = {
baseUrl: 'https://jsonplaceholder.typicode.com'
};

// Runs once globally, even in parallel execution
var auth = karate.callSingle('classpath:auth/get-token.feature');
config.authToken = auth.token;

return config;
}
callonce vs karate.callSingle()
  • callonce runs once per feature
  • karate.callSingle() runs once globally across all features, even in parallel

Multiple Cache Keys

Use different cache keys for different setups:

karate-config.js
function fn() {
var config = {};

// Different cache keys create separate cached results
var adminAuth = karate.callSingle('classpath:auth.feature?admin', {
username: 'admin',
password: 'admin123'
});

var userAuth = karate.callSingle('classpath:auth.feature?user', {
username: 'testuser',
password: 'user123'
});

config.adminToken = adminAuth.token;
config.userToken = userAuth.token;

return config;
}

The ?admin and ?user suffixes create separate cache entries.

Development Mode Caching

Cache authentication tokens to disk for faster development cycles:

karate-config.js
function fn() {
var config = {};

// Enable disk caching in dev mode
if (karate.env === 'dev') {
karate.configure('callSingleCache', { minutes: 15, dir: 'target/auth-cache' });
}

// This result will be cached to disk in dev mode
var auth = karate.callSingle('classpath:expensive-auth.feature');
config.authToken = auth.token;

return config;
}
Pure JSON Only

karate.callSingle() caching requires pure JSON return values. Avoid returning JavaScript functions or Java objects - they cause caching issues in parallel execution.

Hook Summary Table

To Run CodeHow
Before everything (globally once)karate.callSingle() in karate-config.js
Before every ScenarioBackground section, karate-config.js, or configure beforeScenario
Once per Featurecallonce in Background
After every Scenarioconfigure afterScenario
After every Scenario Outlineconfigure afterScenarioOutline
After all Scenarios in Featureconfigure afterFeature (requires Runner API)

Next Steps