Advanced Features
Chaos testing, HAR conversion, error replay, and more
Chaos Testing
Inject artificial latency and failures to test resilience.
# Script options
export const options = {
workers: 10,
duration: '1m',
jitter: '500ms', // Add 0-500ms random latency
drop: 0.05, // Drop 5% of requests
};# CLI flags
$ fusillade run test.js --jitter 500ms --drop 0.05jitter: Adds random delay (0 to specified value) before each request
drop: Probability (0.0-1.0) that a request will be silently dropped
HAR File Conversion
Convert browser recordings (HAR files) into Fusillade test scripts.
# Export HAR from browser
1. Open Chrome DevTools (F12)
2. Go to Network tab
3. Perform the user flow you want to test
4. Right-click → "Save all as HAR with content"# Convert to script
$ fusillade convert --input recording.har --output test.js
# Preview without writing
$ fusillade convert --input recording.har --dry-run# Generated script
// Auto-generated from recording.har
export const options = {
workers: 1,
iterations: 1,
};
export default function() {
// GET https://example.com/
http.get('https://example.com/', {
headers: {
'Accept': 'text/html',
'User-Agent': 'Mozilla/5.0...',
}
});
// POST https://example.com/api/login
http.post('https://example.com/api/login', JSON.stringify({
"username": "user",
"password": "***"
}), {
headers: {
'Content-Type': 'application/json',
}
});
sleep(0.5);
}Traffic Recording Proxy
Record HTTP traffic through a proxy to generate test scripts.
# Start recording proxy on port 8085
$ fusillade record -o recorded-test.js -p 8085
# Configure your app/browser to use http://localhost:8085 as proxy
# Perform actions you want to test
# Press Ctrl+C to stop and generate scriptError Capture & Replay
Capture failed requests during a test run for debugging and replay.
# Capture errors
# Save failed requests to file
$ fusillade run test.js --capture-errors errors.json
# errors.json contains full request details for debugging# Replay failed requests
# Replay one by one
$ fusillade replay errors.json
# Replay in parallel
$ fusillade replay errors.json --parallel
# Export as cURL commands
$ fusillade export errors.json --format curl > debug_commands.shTest Comparison
Compare two test runs to detect performance regressions.
# Export baseline
$ fusillade run test.js --export-json baseline.json
# ... make changes ...
# Export current
$ fusillade run test.js --export-json current.json
# Compare
$ fusillade compare baseline.json current.json
# Output:
# Metric Baseline Current Change
# http_req_duration 145ms 167ms +15.2% ⚠️
# http_req_failed 0.5% 0.8% +60.0% ⚠️
# http_reqs 15,234 14,891 -2.3%Test History
Track test runs over time with the local history database.
# Enable history saving
$ fusillade run test.js --save-history
# View history
$ fusillade history
# ID Date Script Workers Duration P95
# 1 2024-01-15 10:30:00 test.js 10 30s 145ms
# 2 2024-01-15 11:00:00 test.js 50 1m 178ms
# 3 2024-01-15 14:22:00 stress.js 100 5m 234ms
# View specific run
$ fusillade history --show 3
# Limit results
$ fusillade history --limit 10Memory Optimization
Options for running high-concurrency tests without exhausting memory.
export const options = {
workers: 100000,
duration: '10m',
// Discard response bodies (only keep status/headers)
response_sink: true,
// Disable per-endpoint metrics (reduces cardinality)
no_endpoint_tracking: true,
// Auto-throttle spawning when memory is high
memory_safe: true,
// Smaller stack per worker (default 32KB)
stack_size: 16384,
};# CLI equivalent
$ fusillade run test.js -w 100000 \
--response-sink \
--no-endpoint-tracking \
--memory-safeWatch Mode
Automatically re-run tests when script files change.
# Watch for changes and re-run
$ fusillade run test.js --watch
# Great for development - edit script, see results immediatelyScript Validation
Validate scripts without running them.
# Check script syntax and configuration
$ fusillade validate test.js
# Validate with config file
$ fusillade validate test.js -c config.yaml
# Output:
# ✓ Script syntax valid
# ✓ Options parsed successfully
# ✓ Thresholds valid
# ✓ 3 scenarios definedBandwidth Cost Estimation
# Estimate data transfer costs
$ fusillade run test.js --estimate-cost
# Set cost limit (abort if exceeded)
$ fusillade run test.js --estimate-cost 100 # $100 limit
# Output:
# Estimated data transfer: 15.2 GB
# Estimated cost (AWS): $1.37
# Estimated cost (GCP): $1.22Utility Functions
sleep(seconds)Pause execution for N seconds (fractional supported)
sleepRandom(min, max)Pause for random duration between min and max seconds
print(message)Print to console (visible in TUI)
utils.uuid()Generate UUID v4
utils.randomString(length)Random alphanumeric string
utils.randomInt(min, max)Random integer in range
utils.randomItem(array)Random array element
utils.randomEmail()Generate random email address
utils.randomPhone()Generate random US phone number
utils.randomName()Generate random name {first, last, full}
utils.randomDate(startYear, endYear)Generate random date (YYYY-MM-DD)
utils.sequentialId()Unique sequential ID across workers
Crypto Module
crypto.md5(data)MD5 hash as hex string
crypto.sha1(data)SHA1 hash as hex string
crypto.sha256(data)SHA256 hash as hex string
crypto.hmac(algorithm, key, data)HMAC using md5/sha1/sha256
Encoding Module
encoding.b64encode(data)Encode string to base64
encoding.b64decode(data)Decode base64 to string
Console API
Structured logging with log levels.
console.log(msg)Log at INFO level (default)
console.info(msg)Log at INFO level
console.warn(msg)Log at WARN level
console.error(msg)Log at ERROR level
console.debug(msg)Log at DEBUG level (hidden by default)
console.table(array)Display array of objects as table
console.debug('Detailed debugging info'); // Only shown with --log-level debug
console.log('Normal info message');
console.warn('Warning: rate limit approaching');
console.error('Error: request failed');
// Pretty-print tabular data
console.table([
{ name: 'Alice', score: 95 },
{ name: 'Bob', score: 87 },
]);Unit Testing
Built-in unit testing framework for verifying logic.
describe(name, fn)Groups related tests
test(name, fn)Defines a test case
expect(value).toBe(expected)Strict equality check
expect(value).toEqual(expected)Deep equality check (via JSON)
expect(value).toBeTruthy()Checks if value is truthy
describe("Cart Logic", () => {
test("calculates total correctly", () => {
const total = calculateTotal(100, 2);
expect(total).toBe(200);
});
test("applies discount", () => {
const discounted = applyDiscount(100, 0.1);
expect(discounted).toBe(90);
});
});Request Grouping (segment)
Group requests under named categories for cleaner metrics.
segment('Login Flow', () => {
http.post('/login', credentials);
segment('Dashboard', () => {
http.get('/dashboard'); // Metric: "Login Flow::Dashboard::/dashboard"
});
});
// Nested segments create hierarchical namesStats API
Query collected statistics during the test for adaptive scenarios.
export default function() {
http.get('https://api.example.com/data', { name: 'getData' });
// Query stats for a named request
const s = stats.get('getData');
print(`p95: ${s.p95}ms, avg: ${s.avg}ms, count: ${s.count}`);
// Adaptive behavior based on performance
if (s.p95 > 500) {
print('Warning: p95 latency exceeds 500ms');
}
}p95 - 95th percentile latency (ms)
p99 - 99th percentile latency (ms)
avg - Average latency (ms)
count - Total request count
min - Minimum latency (ms)
max - Maximum latency (ms)
Global Variables
__WORKER_ID - Current worker's numeric ID (0-indexed)
__ITERATION - Current iteration number for this worker (0-indexed)
__ENV - Object containing environment variables
__SCENARIO - Name of currently executing scenario
__WORKER_STATE - Per-worker state object that persists across iterations
export default function() {
// Use worker ID to partition test data
const userId = users[__WORKER_ID % users.length];
// Access environment variables
const apiKey = __ENV.API_KEY || 'default-key';
// Track per-worker state across iterations
__WORKER_STATE.loginCount = (__WORKER_STATE.loginCount || 0) + 1;
console.log(`Worker ${__WORKER_ID} iteration ${__ITERATION}, logins: ${__WORKER_STATE.loginCount}`);
// Store session data that persists
if (!__WORKER_STATE.token) {
const res = http.post('/login', credentials);
__WORKER_STATE.token = res.json().token;
}
// Use cached token in subsequent iterations
http.get('/api/data', { headers: { 'Authorization': `Bearer ${__WORKER_STATE.token}` } });
}Automatic .env File Loading
Fusillade automatically loads .env files from the script's directory or current working directory.
# .env file format
API_KEY=your-secret-key
BASE_URL=https://api.example.com
DEBUG=trueShell Completions
# Generate completions for your shell
$ fusillade completion bash >> ~/.bashrc
$ fusillade completion zsh >> ~/.zshrc
$ fusillade completion fish > ~/.config/fish/completions/fusillade.fish
# PowerShell
$ fusillade completion powershell >> $PROFILEJSON Schema Support
Generate JSON Schema for config file validation in your IDE.
# Generate JSON schema for config validation
$ fusillade schema -o fusillade.schema.jsonUse with VS Code YAML extension for autocomplete in YAML config files.