Skip to main content

Chaos Engineering

agnt includes a built-in chaos engineering system for testing how your frontend handles network failures, slow connections, and unreliable APIs. Test the unhappy paths without changing your code.

Full story: Break your API on purpose.

Why Chaos Testing for Frontend?​

Most frontend bugs happen under conditions developers never test:

  • Slow networks - 3G connections, hotel WiFi, subway tunnels
  • Flaky APIs - 500 errors, timeouts, rate limits
  • Race conditions - Responses arriving out of order
  • Stale tabs - Browser tabs open for hours with expired tokens

agnt lets you simulate all of these with a single command.

Quick Start​

# Start proxy, then apply a chaos preset
proxy {action: "start", id: "app", target_url: "http://localhost:3000"}
proxy {action: "chaos", id: "app", chaos_operation: "preset", chaos_preset: "flaky-api"}

Your app now experiences random 500 errors, timeouts, and variable latency. Watch what breaks.

All chaos commands route through proxy {action: "chaos"} with a chaos_operation field that selects what to do. Valid operations: enable, disable, status, set, preset, add_rule, remove_rule, list_rules, stats, clear.

OperationRequired fieldPurpose
presetchaos_presetApply a named bundle of rules
setchaos_configReplace the full rule set (with optional seed)
add_rulechaos_ruleAdd a single rule
remove_rulechaos_rule_idRemove one rule by id
enable / disable—Toggle chaos on/off without losing rules
status / stats—Inspect current state and injection counts
list_rules—List active rules
clear—Remove all rules

Built-in Presets​

PresetWhat It SimulatesUse For
mobile-3g200-2000ms latency, 2% packet lossMobile network testing
mobile-4g50-500ms latency, 0.5% packet lossLTE network testing
flaky-apiRandom 500s, timeouts, variable latencyAPI resilience testing
race-conditionOut-of-order responses, high variance delaysRace condition bugs
stale-tab3-hour delaysToken expiry, stale state
slow-connection5KB/s bandwidth throttlingSlow network handling
connection-drops10% mid-response disconnectsRetry logic testing
data-corruption5% truncated responsesPartial data handling
rate-limited20% 429 errorsRate limit UI testing
auth-failures10% 401/403 errorsAuth error handling
service-degradationMixed latency + errors + truncationGraceful degradation
pressure-testEverything at onceStress testing

Preset Examples​

Test mobile network conditions:

proxy {action: "chaos", id: "app", chaos_operation: "preset", chaos_preset: "mobile-3g"}
# Your app now has 200-2000ms latency and 2% packet loss

Expose race conditions:

proxy {action: "chaos", id: "app", chaos_operation: "preset", chaos_preset: "race-condition"}
# API responses arrive out of order - does your state get corrupted?

Test stale browser tabs:

proxy {action: "chaos", id: "app", chaos_operation: "preset", chaos_preset: "stale-tab"}
# Simulates a tab that's been open for hours - test token refresh

Custom Chaos Rules​

For fine-grained control, use chaos_operation: "set" with a chaos_config that holds the full rule set. set replaces all existing rules:

proxy {
action: "chaos",
id: "app",
chaos_operation: "set",
chaos_config: {
"enabled": true,
"rules": [
{
"id": "api-latency",
"name": "Slow API calls",
"type": "latency",
"enabled": true,
"url_pattern": "/api/.*",
"min_latency_ms": 500,
"max_latency_ms": 3000,
"probability": 0.5
},
{
"id": "checkout-errors",
"name": "Checkout failures",
"type": "http_error",
"enabled": true,
"url_pattern": "/api/checkout",
"error_codes": [500, 503],
"probability": 0.1
}
]
}
}

Chaos Types​

Network Chaos​

TypeDescriptionConfiguration
latencyAdd delays to responsesmin_latency_ms, max_latency_ms, jitter_ms
bandwidthLimit data transfer rate(use slow_drip instead)
packet_lossDrop random requests entirelyprobability
disconnectDrop connection mid-responsedrop_after_percent, drop_after_bytes
slow_dripTrickle bytes slowlybytes_per_ms, chunk_size
timeoutNever respond (simulate timeout)probability

Response Timing​

TypeDescriptionConfiguration
out_of_orderDeliver responses in random orderreorder_min_requests, reorder_max_wait_ms
staleVery long delays (hours)stale_delay_ms

HTTP Errors​

TypeDescriptionConfiguration
http_errorInject HTTP error codeserror_codes[], error_message
rate_limitSimulate 429 rate limiting(use http_error with code 429)

Data Corruption​

TypeDescriptionConfiguration
truncateCut off response bodytruncate_percent (0.0-1.0, portion to keep)
bit_flipRandom byte changes(advanced)
corrupt_jsonMalform JSON responses(advanced)

Rule Configuration​

Matching Criteria​

{
"url_pattern": "/api/users.*", // Regex pattern for URLs
"methods": ["POST", "PUT"], // HTTP methods (empty = all)
"probability": 0.3 // 0.0-1.0, chance of applying
}

Latency Configuration​

{
"type": "latency",
"min_latency_ms": 100, // Minimum delay
"max_latency_ms": 2000, // Maximum delay
"jitter_ms": 500 // Random +/- jitter
}

Slow-Drip (Bandwidth Throttling)​

{
"type": "slow_drip",
"bytes_per_ms": 5, // 5 bytes/ms = 5KB/s
"chunk_size": 10 // Write 10 bytes at a time
}

Connection Drops​

{
"type": "disconnect",
"drop_after_percent": 0.5, // Drop after 50% of body sent
// OR
"drop_after_bytes": 1024 // Drop after 1KB sent
}

Response Reordering​

{
"type": "out_of_order",
"reorder_min_requests": 3, // Batch this many before shuffling
"reorder_max_wait_ms": 500 // Max time to wait for batch
}

Managing Chaos​

Check Status​

proxy {action: "chaos", id: "app", chaos_operation: "status"}

Returns:

{
"enabled": true,
"preset": "flaky-api",
"stats": {
"total_requests": 142,
"affected_count": 38,
"latency_injected_ms": 45000,
"errors_injected": 7,
"drops_injected": 2
}
}

For the injection counters on their own, use chaos_operation: "stats".

Enable / Disable Chaos​

Toggle chaos off without discarding your configured rules, then back on later:

proxy {action: "chaos", id: "app", chaos_operation: "disable"}
proxy {action: "chaos", id: "app", chaos_operation: "enable"}

Clear All Rules​

proxy {action: "chaos", id: "app", chaos_operation: "clear"}

Add or Remove Individual Rules​

Add one rule with add_rule (the rest of the configuration stays intact):

proxy {
action: "chaos",
id: "app",
chaos_operation: "add_rule",
chaos_rule: {
"id": "api-latency",
"type": "latency",
"enabled": true,
"url_pattern": "/api/.*",
"min_latency_ms": 500,
"max_latency_ms": 3000,
"probability": 0.5
}
}

Remove one rule by its id:

proxy {action: "chaos", id: "app", chaos_operation: "remove_rule", chaos_rule_id: "api-latency"}

Real-World Testing Scenarios​

Testing Loading States​

# Add 2-5 second delay to all API calls
proxy {
action: "chaos",
id: "app",
chaos_operation: "set",
chaos_config: {
"enabled": true,
"rules": [{
"id": "slow-everything",
"type": "latency",
"enabled": true,
"min_latency_ms": 2000,
"max_latency_ms": 5000,
"probability": 1.0
}]
}
}

Now verify: Do your loading spinners appear? Is the UI responsive during loads?

Testing Error Handling​

# 50% of API calls fail with server errors
proxy {
action: "chaos",
id: "app",
chaos_operation: "set",
chaos_config: {
"enabled": true,
"rules": [{
"id": "server-errors",
"type": "http_error",
"enabled": true,
"error_codes": [500, 502, 503],
"probability": 0.5
}]
}
}

Now verify: Do error messages appear? Can users retry? Does state stay consistent?

Testing Race Conditions​

# Responses arrive in random order
proxy {action: "chaos", id: "app", chaos_operation: "preset", chaos_preset: "race-condition"}

Now verify: If user types in search and gets responses out of order, does the UI show stale results?

Testing Offline Behavior​

# Drop 100% of requests
proxy {
action: "chaos",
id: "app",
chaos_operation: "set",
chaos_config: {
"enabled": true,
"rules": [{
"id": "offline",
"type": "packet_loss",
"enabled": true,
"probability": 1.0
}]
}
}

Now verify: Does offline detection trigger? Are there helpful error messages?

Testing Token Expiry​

# Return 401 for all API calls
proxy {
action: "chaos",
id: "app",
chaos_operation: "set",
chaos_config: {
"enabled": true,
"rules": [{
"id": "expire-tokens",
"type": "http_error",
"enabled": true,
"url_pattern": "/api/.*",
"error_codes": [401],
"probability": 1.0
}]
}
}

Now verify: Does the app redirect to login? Is state preserved for after re-auth?

Reproducible Chaos​

For consistent test runs, set a random seed inside chaos_config:

proxy {
action: "chaos",
id: "app",
chaos_operation: "set",
chaos_config: {
"enabled": true,
"seed": 12345,
"rules": [ /* ... */ ]
}
}

Same seed = same sequence of chaos decisions.

Integration with Testing​

Manual Exploratory Testing​

  1. Start your dev server and proxy
  2. Apply a chaos preset
  3. Click through your app
  4. Watch for broken states, missing loaders, poor error messages

Automated E2E Tests​

Apply chaos through the agnt MCP tool before driving your E2E suite, then assert that your error and retry UI behaves:

# Before the test run, enable a flaky-API preset on the proxy
proxy {action: "chaos", id: "app", chaos_operation: "preset", chaos_preset: "flaky-api"}
// In Playwright/Cypress, point the browser at the proxy URL and assert resilience
test('handles API errors gracefully', async ({ page }) => {
await page.goto('/dashboard');
// Error states should be visible due to injected chaos
await expect(page.locator('.error-message')).toBeVisible();
await expect(page.locator('.retry-button')).toBeEnabled();
});

When the run finishes, clear chaos with proxy {action: "chaos", id: "app", chaos_operation: "clear"}.

Best Practices​

  1. Start with presets - They cover common scenarios well
  2. Test one thing at a time - Don't combine too many chaos types
  3. Document expected behavior - What SHOULD happen under chaos?
  4. Add chaos to CI - Run a subset of E2E tests with chaos enabled
  5. Use probability < 1.0 - Intermittent failures are harder to handle than consistent ones

See Also​