Skip to main content

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
JSON Key Rules

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 Type Conversion

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'
Financial Calculations

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