Error Injection — aimock
Test your application's error handling with one-shot errors, stream truncation, and timed disconnects. aimock provides three mechanisms for simulating failures.
One-Shot Errors
Queue an error that fires on the next request and auto-removes itself. Useful for testing retry logic.
const mock = new LLMock();
await mock.start();
mock.onMessage("hello", { content: "Hi!" });
// Queue a 429 rate limit error for the next request
mock.nextRequestError(429, {
message: "Rate limit exceeded",
type: "rate_limit_error",
});
// First request → 429 error
const res1 = await fetch(`${mock.url}/v1/chat/completions`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "gpt-4",
messages: [{ role: "user", content: "hello" }],
}),
});
expect(res1.status).toBe(429);
// Second request → normal response (error auto-removed)
const res2 = await fetch(`${mock.url}/v1/chat/completions`, { /* same */ });
expect(res2.status).toBe(200);
Stream Truncation
Abort a streaming response after a specific number of SSE chunks. Tests that your application handles partial streams gracefully.
mock.on(
{ userMessage: "long story" },
{ content: "This is a very long response that will be cut short" },
{ truncateAfterChunks: 3 } // Abort after 3 SSE chunks
);
Timed Disconnect
Disconnect after a specified number of milliseconds. Simulates network timeouts and connection drops.
mock.on(
{ userMessage: "slow" },
{ content: "This response will never complete" },
{ disconnectAfterMs: 100 } // Kill connection after 100ms
);
Error Fixtures in JSON
{
"fixtures": [
{
"match": { "userMessage": "error-test" },
"response": {
"error": {
"message": "Rate limited",
"type": "rate_limit_error"
},
"status": 429
}
},
{
"match": { "userMessage": "partial" },
"response": { "content": "This gets cut off" },
"truncateAfterChunks": 2
},
{
"match": { "userMessage": "timeout" },
"response": { "content": "Never finishes" },
"disconnectAfterMs": 50
}
]
}
Interruption Behavior
-
truncateAfterChunks— counts SSE data lines sent; aborts on the Nth chunk -
disconnectAfterMs— starts a timer when the response begins; kills the connection when it fires - If both are set, whichever fires first wins
-
Interrupted requests are recorded in the journal with
response.interrupted: trueandresponse.interruptReason
nextRequestError() is one-shot: it fires once and auto-removes itself. For
persistent error fixtures, use addFixture() with an error response.
See also: Chaos Testing — for probabilistic failure injection. Chaos testing adds configurable error rates, random latency spikes, and stream corruption that trigger based on probability rather than deterministic fixture matching. Use error injection for specific, reproducible failure scenarios; use chaos testing for resilience testing under unpredictable conditions.