CORE SYNTAX
Expressions
Execute JavaScript functions, query data with XPath and JsonPath, and embed dynamic expressions directly in JSON and XML.
Benefits of Expressions
- JavaScript integration: Use full JavaScript including ES6 features for complex logic
- Query languages: Extract data with XPath for XML and JsonPath for JSON
- Embedded expressions: Inject dynamic values using
#(expression)syntax - Reusable functions: Define JavaScript functions for data transformation and validation
- Built-in utilities: Access Karate's utility functions for filtering, mapping, and data manipulation
Simple Expressions
Execute JavaScript directly for calculations, string operations, and basic conditional logic.
Feature: Basic JavaScript expressions
Scenario: String operations
* def firstName = 'John'
* def lastName = 'Doe'
* def fullName = `${firstName} ${lastName}`
* match fullName == 'John Doe'
* def email = firstName.toLowerCase() + '@example.com'
* match email == 'john@example.com'
Scenario: Number calculations
* def price = 50
* def quantity = 3
* def subtotal = price * quantity
* match subtotal == 150
* def discount = 10
* def total = subtotal - discount
* match total == 140
Scenario: Conditional logic
* def age = 30
* def isAdult = age >= 18
* match isAdult == true
* def discount = age >= 65 ? 0.20 : age >= 18 ? 0.10 : 0
* match discount == 0.10
* def accountType = age >= 65 ? 'senior' : age >= 18 ? 'adult' : 'minor'
* match accountType == 'adult'
Embedded Expressions
Inject dynamic values into JSON and XML using #(expression) syntax. Types are preserved (numbers stay numbers, booleans stay booleans), and you can execute any JavaScript expression inline.
Use #(expression) when you need to:
- Build API request payloads with dynamic values
- Template JSON from files with test-specific data
- Preserve data types (numbers as numbers, not strings)
- Mix static structure with dynamic values
Basic Variable Embedding
Embed simple variables into JSON while preserving their types.
Feature: Basic embedded expressions
Scenario: Embed variables into API request
* def userId = 12345
* def userName = 'john.doe'
* def isActive = true
* def userRequest =
"""
{
id: '#(userId)',
username: '#(userName)',
active: '#(isActive)'
}
"""
* match userRequest.id == 12345
* match userRequest.username == 'john.doe'
* match userRequest.active == true
Embedded Calculations
Execute calculations directly within JSON using embedded expressions.
Feature: Embedded calculations
Scenario: Calculate values in API request
* def basePrice = 100
* def quantity = 5
* def orderRequest =
"""
{
basePrice: '#(basePrice)',
quantity: '#(quantity)',
subtotal: '#(basePrice * quantity)',
tax: '#(basePrice * quantity * 0.08)',
total: '#((basePrice * quantity) * 1.08)'
}
"""
* match orderRequest.subtotal == 500
* match orderRequest.tax == 40
* match orderRequest.total == 540
Conditional Logic in Embedded Expressions
Use ternary operators for conditional values.
Feature: Conditional embedded expressions
Scenario: Apply conditional discount
* def customerType = 'premium'
* def orderAmount = 100
* def invoice =
"""
{
amount: '#(orderAmount)',
customerType: '#(customerType)',
discount: '#(customerType == "premium" ? 15 : 5)',
finalAmount: '#(orderAmount - (customerType == "premium" ? 15 : 5))'
}
"""
* match invoice.discount == 15
* match invoice.finalAmount == 85
Embedded vs Enclosed
Choose between #(expression) for mixing static and dynamic values, or ({ ... }) for fully dynamic structures.
Feature: Embedded vs enclosed JavaScript
Scenario: Compare both approaches
* def userName = 'John'
* def userAge = 30
# Embedded: mix static JSON with dynamic values
* def embedded = { name: '#(userName)', age: '#(userAge)', email: '#(userName.toLowerCase() + "@example.com")' }
# Enclosed: entire object is JavaScript
* def enclosed = ({ name: userName, age: userAge, email: userName.toLowerCase() + '@example.com' })
# Both produce identical results
* match embedded == enclosed
Use embedded #(expression) when you have mostly static JSON with a few dynamic values. Use enclosed ({ ... }) when your entire structure is dynamic or requires complex JavaScript logic.
JavaScript Functions
Define reusable functions for authentication, data generation, and response validation.
Inline Functions
Simple one-line functions for quick transformations.
Feature: Inline JavaScript functions
Scenario: Generate dynamic test data
* def randomId = function(){ return Math.floor(Math.random() * 10000) }
* def uuid = function(){ return java.util.UUID.randomUUID() + '' }
* def userId = randomId()
* def requestId = uuid()
* match userId == '#number'
* match requestId == '#string'
Multi-Line Functions
Use triple quotes for complex logic like data transformation or calculation.
Feature: Multi-line functions
Scenario: Calculate price with tax and discount
* def calculateTotal =
"""
function(price, quantity, discountPercent) {
var subtotal = price * quantity;
var discount = subtotal * (discountPercent / 100);
var taxableAmount = subtotal - discount;
var tax = taxableAmount * 0.08;
return taxableAmount + tax;
}
"""
* def total = calculateTotal(100, 3, 10)
* match total == 291.6
Functions for Dynamic Headers
Generate authentication headers dynamically for each request.
Feature: Dynamic header generation
Scenario: Generate headers with authentication
* def getAuthHeaders =
"""
function() {
var timestamp = new Date().getTime();
var requestId = java.util.UUID.randomUUID() + '';
return {
'X-Request-ID': requestId,
'X-Timestamp': timestamp,
'X-Client-Version': '1.0.0'
};
}
"""
* def headers = getAuthHeaders()
* match headers['X-Request-ID'] == '#string'
* match headers['X-Timestamp'] == '#number'
* match headers['X-Client-Version'] == '1.0.0'
Functions with Array Operations
Use ES6 arrow functions and array methods for data transformation.
Feature: Array transformations
Scenario: Filter and map data
* def users =
"""
[
{ name: 'John', age: 30, active: true },
{ name: 'Jane', age: 25, active: false },
{ name: 'Bob', age: 35, active: true }
]
"""
# Filter active users
* def activeUsers = users.filter(u => u.active)
* match activeUsers == '#[2]'
# Extract names
* def names = users.map(u => u.name)
* match names == ['John', 'Jane', 'Bob']
# Chain operations
* def activeNames = users.filter(u => u.active).map(u => u.name)
* match activeNames == ['John', 'Bob']
Karate Utilities
Access built-in functions through the karate object for common data operations.
Feature: Karate utility functions
Scenario: Common utilities
* def users = [{ name: 'John', age: 30 }, { name: 'Jane', age: 25 }]
# Filter with Karate function
* def filtered = karate.filter(users, function(u) { return u.age > 25 })
* match filtered == '#[1]'
# Map with Karate function
* def names = karate.map(users, function(u) { return u.name })
* match names == ['John', 'Jane']
# Array utilities
* def numbers = [1, 2, 2, 3, 3, 3]
* def unique = karate.distinct(numbers)
* match unique == [1, 2, 3]
# Object utilities
* def keys = karate.keysOf(users[0])
* match keys contains 'name'
* match keys contains 'age'
Karate's Graal JS engine supports full ES6. Use native array methods (map, filter, reduce, find, some, every) directly on arrays. The karate object provides additional utilities like log(), jsonPath(), xmlPath(), distinct(), and sort().
JsonPath Queries
Extract and filter JSON data using JsonPath syntax with wildcards and conditional filters.
Feature: JsonPath operations
Scenario: Extract data from API response
# Simulating a real API response
* def apiResponse =
"""
{
success: true,
data: {
users: [
{ id: 1, name: 'Alice Johnson', role: 'admin', active: true },
{ id: 2, name: 'Bob Smith', role: 'user', active: true },
{ id: 3, name: 'Carol White', role: 'user', active: false }
]
}
}
"""
# Extract all user names using JsonPath
* def allNames = $apiResponse.data.users[*].name
* match allNames == ['Alice Johnson', 'Bob Smith', 'Carol White']
# Get first user
* def firstUser = $apiResponse.data.users[0]
* match firstUser.name == 'Alice Johnson'
# Check response status
* def status = $apiResponse.success
* match status == true
JsonPath Filters
Apply conditional filters to extract specific data from arrays.
Feature: JsonPath filters
Scenario: Filter API response data
* def apiResponse =
"""
{
success: true,
data: {
users: [
{ id: 1, name: 'Alice Johnson', role: 'admin', active: true },
{ id: 2, name: 'Bob Smith', role: 'user', active: true },
{ id: 3, name: 'Carol White', role: 'user', active: false }
]
}
}
"""
# Filter active users only
* def activeUsers = karate.jsonPath(apiResponse, "$.data.users[?(@.active == true)]")
* match activeUsers == '#[2]'
# Extract names of admin users
* def adminNames = karate.jsonPath(apiResponse, "$.data.users[?(@.role == 'admin')].name")
* match adminNames == ['Alice Johnson']
# Filter active users with specific role
* def activeRegularUsers = karate.jsonPath(apiResponse, "$.data.users[?(@.active == true && @.role == 'user')]")
* match activeRegularUsers == '#[1]'
* match activeRegularUsers[0].name == 'Bob Smith'
XPath Queries
Navigate and query XML documents using XPath syntax with attribute filters and predicates.
Feature: XPath operations
Scenario: Basic XPath
* def order =
"""
<order>
<id>12345</id>
<customer>
<name>John Doe</name>
<email>john@example.com</email>
</customer>
<items>
<item>
<product>Laptop</product>
<price>999.99</price>
</item>
<item>
<product>Mouse</product>
<price>29.99</price>
</item>
</items>
</order>
"""
# Extract values using get keyword
* def orderId = get order /order/id
* def customerName = get order /order/customer/name
* match orderId == '12345'
* match customerName == 'John Doe'
# Array access (XPath uses 1-based indexing)
* def firstProduct = get order /order/items/item[1]/product
* match firstProduct == 'Laptop'
Advanced XPath
Use attribute filters, predicates, and node counting for complex queries.
Feature: Advanced XPath
Scenario: XPath with attributes and filters
* def inventory =
"""
<inventory>
<product category="electronics" available="true">
<name>Laptop</name>
<price>999</price>
</product>
<product category="electronics" available="false">
<name>Tablet</name>
<price>599</price>
</product>
<product category="books" available="true">
<name>Guide</name>
<price>49</price>
</product>
</inventory>
"""
# Attribute filters
* def available = karate.xmlPath(inventory, '//product[@available="true"]')
* match available == '#[2]'
# Value conditions
* def expensive = karate.xmlPath(inventory, '//product[price > 500]/name')
* match expensive == ['Laptop', 'Tablet']
# Count nodes
* def total = karate.xmlPath(inventory, 'count(//product)')
* match total == 3
XPath uses 1-based indexing ([1] for first element), unlike JavaScript's 0-based indexing. Use karate.xmlPath() for complex queries with predicates, attributes, and filters.
Dynamic Patterns
Generate test data and create environment-specific configurations using expressions.
Feature: Dynamic data generation
Scenario: Generate test users
* def generateUser =
"""
function(index) {
return {
id: index,
name: 'User' + index,
email: 'user' + index + '@test.com',
active: index % 2 === 0
};
}
"""
* def users = karate.repeat(3, generateUser)
* match users == '#[3]'
* match users[0].name == 'User0'
* match users[1].email == 'user1@test.com'
Scenario: Environment-based configuration
* def env = karate.env || 'dev'
* def config =
"""
{
baseUrl: '#(env == "prod" ? "https://api.example.com" : "https://api-" + env + ".example.com")',
timeout: '#(env == "prod" ? 60000 : 30000)',
debug: '#(env == "dev")'
}
"""
* assert config.timeout > 0
* match config.baseUrl contains env
Quick Reference
Common expression patterns for quick lookup.
| Task | Syntax | Example |
|---|---|---|
| String concatenation | `${var}` or + | `Hello ${name}` |
| Embed variable | #(variable) | { id: '#(userId)' } |
| Conditional value | condition ? true : false | '#(age >= 18 ? "adult" : "minor")' |
| Calculate in JSON | #(expression) | { tax: '#(price * 0.08)' } |
| Call function | functionName(args) | * def result = calculate(10, 20) |
| Filter array | .filter(condition) | users.filter(u => u.active) |
| Map array | .map(transform) | users.map(u => u.name) |
| Extract JsonPath | $.path | $.users[*].name |
| Extract XPath | /path | response/order/id |
| Karate utility | karate.method() | karate.jsonPath(obj, '$.path') |
| Current timestamp | new Date().getTime() | * def now = new Date().getTime() |
| ISO date string | new Date().toISOString() | * def timestamp = new Date().toISOString() |
Next Steps
- Apply expressions in actions: Actions
- Build data-driven tests: Data Driven Tests
- Use expressions in API calls: HTTP Requests
- Master advanced matching: Match Keyword