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: Native JSON support
# Simple JSON objects
* def user = { name: 'John', age: 30, active: true }
* def scores = [85, 92, 78, 90]
* match user.name == 'John'
* match scores[0] == 85
# Complex nested structures
* 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 nested data
* def customerId = order.customer.id
* def firstItem = order.items[0]
* match order.total > 1000
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.
XML Documents
Handle XML as naturally as JSON using either XPath syntax or dot notation for element access.
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 into JSON
* def user =
"""
{
id: '#(userId)',
name: '#(userName)',
email: '#(userName.toLowerCase() + "@example.com")',
created: '#(timestamp)',
active: '#(userId > 0)'
}
"""
* match user.id == 123
* match user.email == 'john@example.com'
* match user.active == true
Scenario: Conditional embedded expressions
* def userType = 'admin'
* def isVip = true
# Use ternary operators for conditional data
* def userProfile =
"""
{
type: "#(userType)",
permissions: "#(userType == 'admin' ? ['read', 'write', 'delete'] : ['read'])",
discountRate: "#(isVip ? 0.15 : 0.05)",
features: "#(userType == 'admin' ? {dashboard: true, reports: true} : {dashboard: false})"
}
"""
* match userProfile.permissions == ['read', 'write', 'delete']
* match userProfile.discountRate == 0.15
JavaScript Integration
Execute JavaScript functions and expressions within data structures for complex transformations, calculations, and array operations.
Feature: JavaScript in data structures
Scenario: JavaScript functions in JSON
* def basePrice = 100
* def taxRate = 0.08
* def order =
{
basePrice: '#(basePrice)',
tax: '#(basePrice * taxRate)',
total: '#(basePrice + (basePrice * taxRate))',
formatted: '#("$" + (basePrice + (basePrice * taxRate)).toFixed(2))',
items: '#([1,2,3].map(i => ({id: i, name: "Item " + i})))'
}
* match order.tax == 8
* match order.total == 108
* match order.formatted == '$108.00'
* match order.items == '#[3]'
Scenario: Advanced array operations
* def products =
[
{ name: 'Laptop', price: 999, category: 'electronics' },
{ name: 'Book', price: 20, category: 'books' },
{ name: 'Phone', price: 599, category: 'electronics' }
]
* def summary =
{
totalProducts: '#(products.length)',
totalValue: '#(products.reduce((sum, p) => sum + p.price, 0))',
avgPrice: '#(products.reduce((sum, p) => sum + p.price, 0) / products.length)',
categories: '#([...new Set(products.map(p => p.category))])',
expensiveItems: '#(products.filter(p => p.price > 500).map(p => p.name))'
}
* match summary.totalProducts == 3
* match summary.totalValue == 1618
* match summary.expensiveItems contains 'Laptop'
Multi-Line Data
Use triple quotes ("""
) for complex or deeply nested data structures without escaping, keeping tests clean and readable.
Feature: Multi-line data
Scenario: Complex nested JSON
* def complexUser =
"""
{
id: 123,
profile: {
personal: {
firstName: 'John',
lastName: 'Doe',
dateOfBirth: '1990-01-15'
},
contact: {
email: 'john.doe@example.com',
phone: '+1-555-0123',
address: {
street: '123 Main St',
city: 'Springfield',
state: 'IL',
zip: '62701'
}
}
},
preferences: {
theme: 'dark',
language: 'en-US',
notifications: {
email: true,
sms: false,
push: true
}
}
}
"""
* match complexUser.profile.personal.firstName == 'John'
* match complexUser.preferences.theme == 'dark'
Scenario: Multi-line XML
* def userXml =
"""
<user>
<id>123</id>
<profile>
<name>John Doe</name>
<email>john@example.com</email>
</profile>
<preferences>
<theme>dark</theme>
<notifications email="true" sms="false"/>
</preferences>
</user>
"""
* match userXml/user/profile/name == 'John Doe'
* match userXml/user/preferences/theme == 'dark'
Scenario: Text templates
# Multi-line text for templates or large payloads
* def emailTemplate =
"""
Dear {{customerName}},
Your order #{{orderNumber}} has been confirmed.
Order total: {{orderTotal}}
Expected delivery: {{deliveryDate}}
Thank you for your business!
"""
# Process template with variables
* def customerName = 'John Doe'
* def orderNumber = 'ORD-123'
* def email = emailTemplate.replace('{{customerName}}', customerName).replace('{{orderNumber}}', orderNumber)
* match email contains 'Dear John Doe'
Type Conversion
Convert between data formats using built-in type keywords: yaml
, csv
, json
, xml
, and string
.
YAML and CSV
Feature: YAML and CSV 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'
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
Handle large numbers and financial calculations with precision using JavaScript's safe integer limits and Java's BigDecimal class.
Feature: Numeric precision
Scenario: Large numbers and decimals
# JavaScript safe integer limit (2^53 - 1)
* def maxSafeInt = 9007199254740991
* match maxSafeInt + 1 == 9007199254740992
# Store numbers larger than safe limit as strings
* def hugeNumber = '9007199254740993'
* match hugeNumber.length == 16
# Standard JavaScript decimal arithmetic
* def price = 99.99
* def taxRate = 0.08
* def total = price + (price * taxRate)
* match total == 107.9892
Scenario: Financial precision with BigDecimal
# Use Java BigDecimal for exact financial calculations
* def precisePrice = new java.math.BigDecimal('99.99')
* def preciseTax = new java.math.BigDecimal('0.08')
* def preciseTotal = precisePrice.add(precisePrice.multiply(preciseTax))
* match preciseTotal.toString() == '107.9892'
# Round to 2 decimal places for currency
* def rounded = preciseTotal.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