Documentation Index
Fetch the complete documentation index at: https://mintlify.com/visible/cruel/llms.txt
Use this file to discover all available pages before exploring further.
Network Testing
Test your application’s resilience to network issues with Cruel’s network simulation capabilities.
Network Latency
Simulate slow network connections:
import { cruel } from 'cruel'
async function fetchAPI() {
const response = await fetch('https://api.example.com/data')
return response.json()
}
// Add 500ms latency
const slowAPI = cruel.network.latency(fetchAPI, 500)
// Variable latency (realistic conditions)
const variableLatency = cruel.network.latency(fetchAPI, [200, 2000])
const data = await slowAPI()
Packet Loss
Simulate dropped packets and connection issues:
import { cruel, CruelNetworkError } from 'cruel'
// 10% packet loss rate
const unstable = cruel.network.packetLoss(fetchAPI, 0.1)
try {
const data = await unstable()
} catch (error) {
if (error instanceof CruelNetworkError) {
console.error('Packet lost:', error.code)
// error.code === 'CRUEL_NETWORK_PACKET_LOSS'
}
}
Connection Issues
Disconnect
DNS Failures
Offline Mode
Simulate random disconnections:import { cruel } from 'cruel'
const flaky = cruel.network.disconnect(fetchAPI, 0.05)
// 5% chance of disconnect error
try {
await flaky()
} catch (error) {
// CruelNetworkError: network disconnect
console.error('Connection lost')
}
Test DNS resolution failures:const dnsFailure = cruel.network.dns(fetchAPI, 0.02)
try {
await dnsFailure()
} catch (error) {
// CruelNetworkError: network dns_failure
console.error('DNS failed')
}
Simulate complete network outage:const offline = cruel.network.offline(fetchAPI)
try {
await offline()
} catch (error) {
// Always throws: CruelNetworkError: network offline
console.error('No connection')
}
Bandwidth Limiting
Simulate slow connections and throttled bandwidth:
import { cruel } from 'cruel'
async function downloadFile() {
const response = await fetch('https://cdn.example.com/large-file.zip')
return response.text()
}
// Limit to 256 kbps (slow 3G)
const throttled = cruel.network.bandwidth(downloadFile, 256)
// Simulate dialup (56 kbps)
const dialup = cruel.network.bandwidth(downloadFile, 56)
const start = Date.now()
const data = await throttled()
console.log(`Downloaded in ${Date.now() - start}ms`)
// Time increases based on response size and bandwidth limit
Network Presets
Use realistic network condition presets:
// Slow network: 1-5 second delays with jitter
const slow = cruel.network.slow(fetchAPI)
Testing with Bun
Comprehensive network resilience tests:
import { cruel, CruelNetworkError } from 'cruel'
import { describe, test, beforeEach, expect } from 'bun:test'
beforeEach(() => {
cruel.reset()
})
describe('API client network resilience', () => {
async function fetchData() {
const response = await fetch('https://api.example.com/data')
if (!response.ok) throw new Error('Request failed')
return response.json()
}
test('handles packet loss', async () => {
const lossy = cruel.network.packetLoss(fetchData, 1)
try {
await lossy()
expect(true).toBe(false)
} catch (error) {
expect(error).toBeInstanceOf(CruelNetworkError)
expect(error.code).toBe('CRUEL_NETWORK_PACKET_LOSS')
}
})
test('tolerates high latency', async () => {
const slow = cruel.network.latency(fetchData, 2000)
const start = Date.now()
await slow()
const elapsed = Date.now() - start
expect(elapsed).toBeGreaterThanOrEqual(2000)
})
test('retries on disconnect', async () => {
let attempts = 0
const fetchWithCount = async () => {
attempts++
const response = await fetch('https://api.example.com/data')
return response.json()
}
const flaky = cruel.network.disconnect(fetchWithCount, 0.5)
const resilient = cruel.retry(flaky, {
attempts: 3,
delay: 100,
retryIf: (error) => error instanceof CruelNetworkError
})
try {
await resilient()
} catch {
// May still fail after retries
}
expect(attempts).toBeGreaterThanOrEqual(1)
})
test('respects timeout on slow connections', async () => {
const verySlow = cruel.network.latency(fetchData, 5000)
const withTimeout = cruel.withTimeout(verySlow, { ms: 1000 })
try {
await withTimeout()
expect(true).toBe(false)
} catch (error) {
expect(error.name).toBe('CruelTimeoutError')
}
})
test('handles bandwidth limits on large responses', async () => {
const largeDownload = async () => {
return 'x'.repeat(32 * 1024) // 32KB
}
const throttled = cruel.network.bandwidth(largeDownload, 256)
const start = Date.now()
await throttled()
const elapsed = Date.now() - start
// Should take approximately (32KB * 8 bits) / (256 kbps) = ~1000ms
expect(elapsed).toBeGreaterThanOrEqual(900)
})
})
Mobile Network Simulation
Simulate real-world mobile conditions:
import { cruel } from 'cruel'
// Play a mobile network scenario
cruel.scenario('mobileNetwork', {
chaos: {
delay: [500, 2000],
fail: 0.2,
timeout: 0.1
},
duration: 30000 // 30 seconds
})
cruel.play('mobileNetwork')
// Your app code runs with mobile network conditions
for (let i = 0; i < 10; i++) {
try {
const data = await fetchAPI()
console.log('Success:', data)
} catch (error) {
console.error('Failed:', error.message)
}
await new Promise(r => setTimeout(r, 1000))
}
cruel.stop()
Combining Network Chaos
Layer multiple network issues for realistic testing:
import { cruel } from 'cruel'
let fn = fetchAPI
// Add multiple layers
fn = cruel.network.latency(fn, [100, 500])
fn = cruel.network.packetLoss(fn, 0.05)
fn = cruel.network.disconnect(fn, 0.02)
// Now has: latency, packet loss, and disconnects
try {
const data = await fn()
} catch (error) {
console.error('Network error:', error.message)
}
Integration with HTTP Intercepts
Combine network chaos with HTTP-level chaos:
import { cruel } from 'cruel'
cruel.patchFetch()
cruel.intercept('api.example.com', {
delay: [100, 500], // Network latency
rateLimit: 0.1, // HTTP 429 errors
status: [500, 502, 503] // Server errors
})
try {
const response = await fetch('https://api.example.com/data')
const data = await response.json()
} catch (error) {
console.error('Failed:', error)
}
cruel.unpatchFetch()
Next Steps