CORE SYNTAX
Data Types
Handle JSON, XML, YAML, and CSV as native data types with embedded expressions, JavaScript integration, and automatic type conversion.
Benefits of Native Data Types
- Zero parsing required: Work with JSON and XML directly without string manipulation
- Embedded expressions: Inject dynamic values using
#(expression)syntax - JavaScript integration: Execute JavaScript within data structures for complex transformations
- Automatic conversion: Switch between JSON, XML, YAML, and CSV seamlessly
- File-based data: Load test data from external files with automatic type detection
JSON Objects
Create and manipulate JSON data directly in tests using Karate's lenient JSON parser, which allows cleaner syntax without requiring quotes around simple keys.
Feature: JSON data types
Scenario: Create and work with JSON
# Simple objects and arrays
* def user = { name: 'John', age: 30, active: true }
* def scores = [85, 92, 78, 90]
* match user.name == 'John'
* match scores[0] == 85
# Nested structure
* def order =
"""
{
id: 'ord_123',
customer: { id: 456, name: 'Jane' },
items: [
{ product: 'laptop', price: 999.99, qty: 1 },
{ product: 'mouse', price: 29.99, qty: 2 }
],
total: 1059.97
}
"""
# Access + validate
* def customerId = order.customer.id
* def firstItem = order.items[0]
* assert order.total > 1000
# Modify JSON (preferred: set)
* set user.role = 'admin'
* match user == { name: 'John', age: 30, active: true, role: 'admin' }
Most keys don't need quotes, but special characters like hyphens require them: { 'Content-Type': 'application/json' }. Karate's lenient parser reduces noise by allowing unquoted simple keys, matching JavaScript object syntax.
Inject variables into multi-line JSON using #(...). Omit quotes to preserve the original type.
* def userId = 42
* def payload =
"""
{
id: #(userId),
note: 'created by test'
}
"""
* match payload.id == 42
XML Documents
Karate treats XML as a first-class type. Use XPath for selection.
Use match for assertions with slash paths, and xpath(xml, '...') when you need to extract values into variables.
For namespaced XML, configure a prefix first.
Feature: XML data types
Scenario: Native XML support
# Simple XML documents
* def user = <user><id>123</id><name>John</name></user>
* match user/user/id == '123'
# Complex XML with namespaces
* def order =
"""
<order xmlns="http://example.com/orders">
<id>ord_123</id>
<customer>
<id>456</id>
<name>Jane Doe</name>
</customer>
<items>
<item>
<product>laptop</product>
<price>999.99</price>
</item>
</items>
</order>
"""
# Access XML data using XPath or dot notation
* def orderId = order/order/id
* def customerName = order.order.customer.name
* match orderId == 'ord_123'
* match customerName == 'Jane Doe'
Embedded Expressions
Inject dynamic values directly into JSON or XML structures using #(expression) syntax, eliminating string concatenation and complex variable manipulation.
Feature: Embedded expressions
Scenario: Dynamic JSON with embedded expressions
* def userId = 123
* def userName = 'John'
* def timestamp = new Date().toISOString()
# Embed variables and expressions directly into JSON
* def user =
"""
{
id: #(userId),
name: #(userName),
email: #(userName.toLowerCase() + '@example.com'),
created: #(timestamp),
active: #(userId > 0)
}
"""
# We don't pin the exact timestamp; just assert it's a string
Then match user ==
"""
{
id: 123,
name: 'John',
email: 'john@example.com',
created: '#string',
active: true
}
"""
Feature: Embedded expressions (conditional)
Scenario: Conditional embedded expressions
* def userType = 'admin'
* def isVip = true
* def permissions = userType == 'admin' ? ['read', 'write', 'delete'] : ['read']
* def features = userType == 'admin' ? { dashboard: true, reports: true } : { dashboard: false }
* def discountRate = isVip ? 0.15 : 0.05
* def userProfile =
"""
{
"type": #(userType),
"permissions": #(permissions),
"discountRate": #(discountRate),
"features": #(features)
}
"""
Then match userProfile ==
"""
{
"type": "admin",
"permissions": ["read", "write", "delete"],
"discountRate": 0.15,
"features": { "dashboard": true, "reports": true }
}
"""
JavaScript Integration
Execute JavaScript functions and expressions within data structures for complex transformations, calculations, and array operations.
Feature: JavaScript in data structures
Scenario: JavaScript expressions in JSON
* def basePrice = 100
* def taxRate = 0.08
# Compute values outside JSON if expressions contain JS operators
* def total = basePrice + (basePrice * taxRate)
* def formatted = '$' + total.toFixed(2)
* def items = [1, 2, 3].map(i => ({ id: i, name: 'Item ' + i }))
* def order =
"""
{
"basePrice": #(basePrice),
"tax": #(basePrice * taxRate),
"total": #(total),
"formatted": #(formatted),
"items": #(items)
}
"""
Then match order.tax == 8
And match order.total == 108
And match order.formatted == '$108.00'
And match order.items == '#[3]'
Multi-Line Data
Karate lets you define multi-line data structures using triple quotes (""").
This is ideal for large JSON payloads, XML snippets, or text templates.
Feature: Multi-line JSON
Scenario: Define and verify nested JSON
* def user =
"""
{
"id": 123,
"profile": {
"name": "John Doe",
"email": "john.doe@example.com"
},
"preferences": {
"theme": "dark",
"notifications": { "email": true, "sms": false }
}
}
"""
Then match user.profile.name == 'John Doe'
And match user.preferences.theme == 'dark'
Type Conversion
automatically convert data between formats using type keywords such as yaml, csv, json, xml, and string. This makes it easy to load structured data directly into your tests.
YAML and CSV
Feature: YAML and JSON conversion
Scenario: YAML to JSON
* yaml yamlData =
"""
users:
- name: John
age: 30
active: true
- name: Jane
age: 25
active: false
settings:
theme: dark
language: en
"""
* match yamlData.users[0].name == 'John'
* match yamlData.settings.theme == 'dark'
Feature: CSV and JSON conversion
Scenario: CSV to JSON
* csv csvData =
"""
name,age,active
John,30,true
Jane,25,false
Bob,35,true
"""
* match csvData == '#[3]'
* match csvData[0] == { name: 'John', age: '30', active: 'true' }
* match csvData[1].name == 'Jane'
# CSV values are strings - convert if needed
* def age = parseInt(csvData[0].age)
* match age == 30
CSV data imports as strings. Values like age: '30' and active: 'true' are strings, not numbers or booleans. Convert explicitly using parseInt() or parseFloat() for numeric operations.
JSON and XML Conversion
Feature: Format conversion
Scenario: Convert between formats
* def userJson = { id: 123, name: 'John', active: true }
# Convert JSON to XML
* xml userXml = userJson
* match userXml/root/id == '123'
* match userXml/root/name == 'John'
# Convert XML back to JSON
* json convertedBack = userXml
* match convertedBack.root.id == '123'
# Convert to string for debugging
* string userString = userJson
* match userString contains '"name":"John"'
File-Based Data
Load test data from external files to separate data from test logic and keep feature files clean.
Feature: File-based data
Scenario: Load data from files
# JSON files auto-parse to native objects
* def userData = read('classpath:data/user.json')
* match userData.name == '#string'
# XML files auto-parse to XML objects
* def configXml = read('classpath:config/settings.xml')
* match configXml/config/timeout == '#present'
# CSV files auto-convert to JSON arrays
* def csvUsers = read('classpath:data/users.csv')
* match csvUsers == '#[]'
# YAML files auto-convert to JSON
* def yamlConfig = read('classpath:config/app.yaml')
* match yamlConfig.database == '#object'
# Text files load as strings
* def template = read('classpath:templates/email.txt')
* match template contains 'Dear'
# JavaScript files load as reusable functions
* def utils = read('classpath:helpers/string-utils.js')
* def result = utils.capitalize('karate')
* match result == 'Karate'
Numeric Precision
Karate supports both JavaScript-style arithmetic (fast, approximate) and Java’s BigDecimal (precise, financial-grade). Use BigDecimal when you need exact decimal accuracy — for example, in money or percentage calculations.
Feature: Numeric precision with BigDecimal
Scenario: Accurate financial calculation
* def price = new java.math.BigDecimal('99.99')
* def tax = new java.math.BigDecimal('0.08')
* def total = price.add(price.multiply(tax))
* match total.toString() == '107.9892'
* def rounded = total.setScale(2, java.math.RoundingMode.HALF_UP)
* match rounded.toString() == '107.99'
JavaScript floating-point arithmetic can produce rounding errors. For financial calculations requiring exact precision, use Java's BigDecimal class. Always pass numbers as strings to BigDecimal constructors: new java.math.BigDecimal('99.99').
Next Steps
- Build dynamic tests with expressions: Expressions
- Manipulate data using keywords: Actions
- Use data types in API requests: HTTP Requests
- Drive tests with data: Data Driven Tests