RUNNING TESTS
Debugging
Debug tests quickly using print statements, IDE breakpoints, and built-in inspection tools—no external debuggers required.
Benefits of Karate Debugging
- Zero setup: No external debugger installation or configuration needed
- Built-in pretty printing: Automatic JSON/XML formatting for readability
- IDE integration: Native support for VS Code and IntelliJ breakpoints
- Always visible output: Print statements appear in console and HTML reports
- No performance overhead: Debug features don't slow down production test runs
Simple Print Debugging
Start with the most straightforward approach—print statements for quick inspection.
Feature: Quick debugging
Scenario: Debug with print
* def user = { id: 123, name: 'Alice' }
* print 'Testing user:', user.name
Given url baseUrl + '/users/' + user.id
* print 'Request URL:', baseUrl + '/users/123'
When method get
* print 'Status:', responseStatus
* print 'Response time:', responseTime, 'ms'
Then status 200
Variable Inspection
Use built-in functions to inspect complex data structures and understand test state.
Feature: Inspect variables
Scenario: Debug complex objects
* def order = { id: 'ord_123', items: [{ name: 'Laptop', price: 999 }], total: 999 }
# Pretty print for readability
* print 'Order data:', karate.pretty(order)
# Inspect object structure
* print 'Available keys:', karate.keysOf(order)
* print 'Items count:', order.items.length
# Type checking
* print 'Order type:', karate.typeOf(order)
* print 'Total type:', karate.typeOf(order.total)
Use print
for always-visible output in console and reports. Use karate.log()
for debug-level messages that can be suppressed via logging configuration.
IDE Debugging
VS Code Breakpoints
Set breakpoints in JavaScript functions and step through code execution.
Feature: VS Code debugging
Background:
* def calculateDiscount =
"""
function(price, isVip) {
var discount = 0;
if (isVip) {
discount = price * 0.15; // Set breakpoint here
} else {
discount = price * 0.05;
}
return discount;
}
"""
Scenario: Debug discount calculation
* def price = 100
* def isVip = true
* def discount = calculateDiscount(price, isVip)
* match discount == 15
IntelliJ Integration
Debug tests directly from IntelliJ using JUnit integration.
@Test
void debugInIntelliJ() {
// Right-click and select "Debug"
Karate.run("problematic-feature")
.karateEnv("dev")
.relativeTo(getClass());
}
Debug Strategies
Isolate the Problem
Narrow down issues by testing components independently.
Feature: Problem isolation
@debug
Scenario: Test step by step
# Step 1: Verify environment
* print 'Environment:', karate.env
* print 'Base URL:', baseUrl
# Step 2: Test connectivity
Given url baseUrl + '/health'
When method get
* print 'Health check:', responseStatus
Then status 200
# Step 3: Test authentication
* call read('authenticate.feature')
* print 'Auth token valid:', authToken != null
# Step 4: Test target endpoint
Given url baseUrl
And path 'problematic/endpoint'
When method get
* print 'Endpoint status:', responseStatus
Step-by-Step Analysis
Enable detailed logging to see exactly what Karate sends and receives.
Feature: Detailed request/response logging
Scenario: Analyze HTTP traffic
* configure logPrettyRequest = true
* configure logPrettyResponse = true
* def userData = { name: 'Alice', email: 'alice@example.com' }
* print 'Sending data:', karate.pretty(userData)
Given url baseUrl
And path 'users'
And request userData
* print 'Full URL:', baseUrl + '/users'
When method post
* print 'Response time:', responseTime, 'ms'
Then status 201
* print 'Created user:', response
Set .parallel(1)
in your test runner to execute sequentially when debugging. Parallel execution interleaves print statements, making output hard to follow.
Common Debugging Patterns
Debug Authentication Flows
Track authentication through multiple steps to identify where it breaks.
Feature: Debug authentication
Scenario: Debug login flow
* print 'Step 1: Request auth token'
Given url baseUrl
And path 'auth/login'
And request { username: 'alice', password: 'secret' }
When method post
* print 'Login status:', responseStatus
* print 'Token received:', response.token != null
* def token = response.token
* print 'Step 2: Use token for API call'
Given url baseUrl
And path 'users/me'
And header Authorization = 'Bearer ' + token
When method get
* print 'Authenticated request status:', responseStatus
Debug JSON Path Issues
Understand why JSON path expressions fail by inspecting data structure.
Feature: Debug JSON path
Scenario: Troubleshoot path expressions
* def response = { data: { users: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }] } }
# Debug step by step
* print 'Full response:', karate.pretty(response)
* print 'Data level:', response.data
* print 'Users array:', response.data.users
* print 'First user:', response.data.users[0]
# Test JSON path
* def result = karate.jsonPath(response, '$.data.users[?(@.id==1)]')
* print 'JSON path result:', result
* match result[0].name == 'Alice'
Debug Match Failures
Get detailed information when assertions fail.
Feature: Debug match failures
Scenario: Understand match errors
* def actual = { id: 123, name: 'Alice', role: 'admin', extra: 'field' }
* def expected = { id: '#number', name: '#string' }
# Use karate.match for detailed error info
* def matchResult = karate.match(actual, expected)
* if (!matchResult.pass) print 'Match failed:', matchResult.message
# Use contains for partial matching
* match actual contains expected
* print 'Partial match succeeded'
# Debug exact match failure
* print 'Actual keys:', karate.keysOf(actual)
* print 'Expected keys:', karate.keysOf(expected)
Debug Flaky Tests
Identify intermittent failures by adding retry logging and timing information.
Feature: Debug flaky tests
Scenario: Track retry attempts
* def attempt = 0
* def maxAttempts = 3
Given url baseUrl
And path 'unstable/endpoint'
And retry until responseStatus == 200 || attempt++ && karate.log('Retry attempt', attempt)
When method get
* print 'Succeeded after', attempt, 'attempts'
* print 'Response time:', responseTime, 'ms'
Then status 200
Log Configuration
Basic Logback Setup
Create logback-test.xml
in src/test/resources
for detailed logging.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Debug level for Karate -->
<logger name="com.intuit.karate" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Log Levels
- DEBUG: Complete request/response payloads, perfect for troubleshooting
- INFO: Basic execution information, good for normal test runs
- WARN: Warnings and timeouts only
- ERROR: Failures and exceptions only
Debug Tools and Utilities
Built-in Functions
Feature: Debug utilities
Scenario: Use Karate debug functions
* def data = { nested: { value: 'test', count: 42 } }
# Pretty print JSON
* print karate.pretty(data)
# Get object keys
* print karate.keysOf(data)
* print karate.keysOf(data.nested)
# Type checking
* print karate.typeOf(data)
* print karate.typeOf(data.nested.count)
# Size/length
* def array = [1, 2, 3, 4, 5]
* print 'Array length:', array.length
Conditional Debug Output
Enable debug output only when needed using environment variables.
Feature: Conditional debugging
Background:
* def debug = karate.properties['debug'] == 'true'
* def debugLog = function(msg, data) { if (debug) karate.log(msg, data) }
Scenario: Conditional logging
* debugLog('Starting test with user', { id: 123 })
Given url baseUrl
And path 'users/123'
When method get
* debugLog('Response received', response)
Then status 200
Error Message Analysis
Common error patterns and how to debug them:
JSON Path Errors
Error: $.user.id
path not found
Debug:
* print 'Full response:', karate.pretty(response)
* print 'Response keys:', karate.keysOf(response)
Connection Failures
Error: Connection timeout or refused
Debug:
* print 'Target URL:', baseUrl
* print 'Response status:', responseStatus
* configure connectTimeout = 30000
* configure readTimeout = 30000
Assertion Failures
Error: Match failed for complex object
Debug:
* print 'Expected:', expected
* print 'Actual:', actual
* def diff = karate.match(actual, expected)
* print 'Match result:', diff
Next Steps
Master debugging and continue with related topics:
- Configure advanced logging: Java API & Utilities
- Analyze test execution: Test Reports
- Debug parallel runs: Parallel Execution
- Learn IDE features: VS Code or IntelliJ
- Troubleshoot specific issues: FAQ