Skip to main content

ADVANCED

Conditional Logic

What You'll Learn

  • Implement if-else logic and conditional execution in tests
  • Use abort and fail to control test flow
  • Create dynamic test behavior based on runtime conditions
  • Handle different environments and configurations conditionally
  • Build utility functions for common conditional patterns
  • Implement switch-case logic and complex decision trees

Overview

Conditional logic allows your tests to adapt to different scenarios, environments, and runtime conditions. Karate provides various mechanisms for implementing conditional behavior, from simple if-else statements to complex decision trees.

Basic Conditional Execution

If Statements

Execute code conditionally using if statements:

Feature: Conditional execution

Scenario: Basic if conditions
* if (responseStatus == 404) karate.log('Resource not found')
* if (response.items.length == 0) karate.fail('No items returned')
* if (environment == 'prod') configure ssl = true

# Multi-line if blocks
* eval
"""
if (response.status == 'pending') {
karate.log('Status is pending, waiting...');
java.lang.Thread.sleep(2000);
karate.call('check-status.feature');
}
"""
```gherkin

### Ternary Operators

Use ternary operators for simple conditional assignments:

```gherkin
Scenario: Ternary operations
* def endpoint = environment == 'prod' ? '/api/v1' : '/api/test'
* def timeout = slowSystem ? 10000 : 5000
* def authToken = isAuthenticated ? token : null

# Nested ternary
* def priority = severity == 'critical' ? 'high' : severity == 'major' ? 'medium' : 'low'
```gherkin

## Abort and Fail

### Using karate.abort()

Exit a scenario without failing the test:

```gherkin
Scenario: Conditional abort
# Skip scenario for certain environments
* if (environment == 'local') karate.abort()

# Skip if precondition not met
* url apiUrl + '/check-ready'
* method get
* if (responseStatus != 200) karate.abort()

# Main test logic
* url apiUrl + '/main-test'
* method post
* status 200
```gherkin

### Using karate.fail()

Explicitly fail a test with custom message:

```gherkin
Scenario: Conditional failure
* url apiUrl + '/critical-operation'
* method post
* status 200

# Fail with descriptive message
* if (!response.success) karate.fail('Critical operation failed: ' + response.error)

# Multiple failure conditions
* if (response.errors && response.errors.length > 0) {
def errorMsg = 'Validation errors: ' + response.errors.join(', ')
karate.fail(errorMsg)
}
```gherkin

## Complex Conditional Flows

### Switch-Case Logic

Implement switch-case patterns using JavaScript:

```gherkin
Background:
* def handleStatus =
"""
function(status) {
switch(status) {
case 'pending':
return { action: 'wait', timeout: 5000 };
case 'processing':
return { action: 'poll', interval: 1000 };
case 'completed':
return { action: 'validate', checkData: true };
case 'failed':
return { action: 'retry', maxAttempts: 3 };
default:
return { action: 'error', message: 'Unknown status' };
}
}
"""

Scenario: Switch-case execution
* url apiUrl + '/status'
* method get
* def decision = handleStatus(response.status)

* if (decision.action == 'wait') java.lang.Thread.sleep(decision.timeout)
* if (decision.action == 'poll') call read('poll-status.feature') { interval: decision.interval }
* if (decision.action == 'retry') call read('retry-operation.feature') { attempts: decision.maxAttempts }
* if (decision.action == 'error') karate.fail(decision.message)
```gherkin

### Decision Trees

Build complex decision trees:

```gherkin
* def makeDecision =
"""
function(context) {
// Level 1: Check environment
if (context.env === 'prod') {
// Level 2: Check user type
if (context.userType === 'admin') {
return { test: 'full', validate: 'strict' };
} else if (context.userType === 'user') {
return { test: 'limited', validate: 'normal' };
}
} else if (context.env === 'staging') {
// Different logic for staging
if (context.feature === 'experimental') {
return { test: 'experimental', validate: 'loose' };
}
}
// Default
return { test: 'basic', validate: 'minimal' };
}
"""

Scenario: Complex decision making
* def context = { env: karate.env, userType: 'admin', feature: 'standard' }
* def decision = makeDecision(context)
* print 'Decision:', decision

* if (decision.test == 'full') call read('full-test-suite.feature')
* if (decision.validate == 'strict') call read('strict-validation.feature')
```gherkin

## Environment-Based Logic

### Environment-Specific Behavior

Adapt tests to different environments:

```gherkin
Feature: Environment-aware testing

Background:
* def env = karate.env || 'dev'

# Environment-specific configuration
* if (env == 'prod') configure ssl = true
* if (env == 'local') configure proxy = 'http://localhost:8888'
* if (env != 'prod') configure report = { showLog: true, showAllSteps: true }

Scenario: Environment-specific endpoints
* def baseUrl =
"""
{
'prod': 'https://api.production.com',
'staging': 'https://api.staging.com',
'dev': 'http://localhost:3000'
}
"""

* url baseUrl[env] + '/endpoint'
* method get
* status 200

# Environment-specific validation
* if (env == 'prod') match response.version == 'v2.0'
* if (env == 'dev') match response.debug == '#present'
```gherkin

### Feature Flags

Handle feature flags conditionally:

```gherkin
Background:
* url configUrl + '/features'
* method get
* status 200
* def features = response

Scenario: Feature flag testing
# Test new feature if enabled
* if (features.newCheckout.enabled) {
call read('test-new-checkout.feature')
} else {
call read('test-legacy-checkout.feature')
}

# Skip tests for disabled features
* if (!features.analytics.enabled) karate.abort()

# Different validation based on feature state
* def expectedFields = features.extendedProfile.enabled
? ['name', 'email', 'phone', 'address', 'preferences']
: ['name', 'email']
* match response.fields == expectedFields
```gherkin

## Data-Driven Conditions

### Conditional Data Processing

Process data conditionally:

```gherkin
Scenario: Process data based on type
* def processItem =
"""
function(item) {
if (item.type === 'user') {
item.processed = true;
item.role = item.role || 'default';
} else if (item.type === 'admin') {
item.processed = true;
item.permissions = ['read', 'write', 'delete'];
} else {
item.processed = false;
item.error = 'Unknown type';
}
return item;
}
"""

* def items = [
{ type: 'user', name: 'John' },
{ type: 'admin', name: 'Jane' },
{ type: 'unknown', name: 'Bob' }
]

* def processed = items.map(processItem)
* match processed[0].role == 'default'
* match processed[1].permissions == ['read', 'write', 'delete']
* match processed[2].error == 'Unknown type'
```gherkin

### Dynamic Validation

Apply different validation rules conditionally:

```gherkin
Scenario: Conditional validation
* def validateResponse =
"""
function(response, context) {
var errors = [];

// Always validate required fields
if (!response.id) errors.push('Missing id');
if (!response.status) errors.push('Missing status');

// Conditional validation based on status
if (response.status === 'completed') {
if (!response.completedAt) errors.push('Missing completedAt');
if (!response.result) errors.push('Missing result');
} else if (response.status === 'failed') {
if (!response.error) errors.push('Missing error');
if (!response.failedAt) errors.push('Missing failedAt');
}

// Environment-specific validation
if (context.env === 'prod' && !response.signature) {
errors.push('Missing signature in production');
}

return errors;
}
"""

* def errors = validateResponse(response, { env: karate.env })
* if (errors.length > 0) karate.fail('Validation errors: ' + errors.join(', '))
```gherkin

## Utility Functions

### Common Conditional Patterns

Create reusable conditional utilities:

```gherkin
Background:
# Retry with condition
* def retryIf =
"""
function(condition, action, maxAttempts) {
for (var i = 0; i < maxAttempts; i++) {
var result = action();
if (!condition(result)) {
return result;
}
if (i < maxAttempts - 1) {
java.lang.Thread.sleep(1000);
}
}
karate.fail('Max attempts reached');
}
"""

# Execute if not null
* def executeIfPresent =
"""
function(value, action) {
if (value !== null && value !== undefined) {
return action(value);
}
return null;
}
"""

# Choose first valid
* def firstValid =
"""
function() {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] !== null && arguments[i] !== undefined) {
return arguments[i];
}
}
return null;
}
"""

Scenario: Use utility functions
# Retry if status is pending
* def checkStatus = function() {
return karate.call('get-status.feature').response
}
* def isPending = function(resp) { return resp.status === 'pending' }
* def result = retryIf(isPending, checkStatus, 5)

# Execute only if token exists
* def token = executeIfPresent(response.token, function(t) {
return 'Bearer ' + t;
})

# Use first available value
* def endpoint = firstValid(
karate.properties['custom.endpoint'],
java.lang.System.getenv('API_ENDPOINT'),
'https://default.api.com'
)
```gherkin

## Error Handling Conditions

### Try-Catch Patterns

Handle errors conditionally:

```gherkin
Scenario: Error handling
* def safeCall =
"""
function(feature, fallback) {
try {
return karate.call(feature);
} catch (e) {
karate.log('Error calling feature:', e.message);
if (fallback) {
return karate.call(fallback);
}
return { error: e.message };
}
}
"""

# Try primary, fallback to secondary
* def result = safeCall('primary-service.feature', 'fallback-service.feature')

# Handle based on success/failure
* if (result.error) {
print 'Using cached data due to error:', result.error
def data = read('classpath:cached-data.json')
} else {
def data = result.response
}
```gherkin

## Best Practices

### Clear Conditions

```gherkin
# ✅ Good: Clear, readable conditions
* if (response.status == 'active' && response.verified == true)

# ❌ Avoid: Complex nested conditions
* if ((a && b) || (c && !d) || (e && f && g))

# ✅ Better: Extract complex logic
* def shouldProcess = function() {
return (a && b) || (c && !d) || (e && f && g);
}
* if (shouldProcess())
```gherkin

### Meaningful Messages

```gherkin
# ✅ Good: Descriptive failure messages
* if (!response.data) karate.fail('No data returned from API')

# ❌ Avoid: Generic messages
* if (!response.data) karate.fail('Test failed')
```gherkin

## Next Steps

- Learn about [Hooks and Lifecycle](/docs/advanced/hooks) for test orchestration
- Explore [Debugging and Troubleshooting](/docs/advanced/debugging) techniques
- Understand [Test Organization](/docs/reusability/calling-features) patterns