šØ Mocking Network Failures, Retries & Edge Cases in Jest
It can mock storage, fake events, spy on functions, and even travel through time.
šØ Mocking Network Failures, Retries & Edge Cases inĀ Jest

š§ When the Internet BetraysĀ You
Our Expense Tracker is becoming smart.
It can mock storage, fake events, spy on functions, and even travel through time.
But there is one thing it still cannot control.
One thing that has embarrassed every developer at least once:
š The Internet.
Yesāāāthe same network that works perfectly
until youāre showing your feature to your teamā¦
and suddenly the API returns:
āNetwork Errorā
āTimeoutā
āUnexpected token < in JSON at position 0ā
Your soul leaves your body.
Your teammates stare.
You whisper:
āBut⦠but this worked yesterdayā¦ā
Testing MUST simulate this pain.
Because the real world will definitely simulate it for you later.
š” Why Network Failures FeelĀ Personal

When your code fails, you blame yourself.
When the network fails, you blame life.
Everyone has seen:
- ā ļø Slow responses
- ā Random 500 errors
- š Infinite loading spinners
- š§Ø āWorks on my machineā moments
- š§āāļø API suddenly returning HTML instead of JSON
- š§ Freeze ā retry ā freeze ā retry
All of this is deeply relatable.
This is why mocking failures keeps readers hookedāāātheyāve lived this suffering.
š§Ŗ Step 1āāāThe Expense Trackerās āRetryĀ Logicā
Letās give our app a new ability:
Try again when the API fails.
š fetchRetry.js
const axios = require('axios');
exports.fetchExpensesWithRetry = async (url, attempts = 3) => {
for (let i = 0; i < attempts; i++) {
try {
const res = await axios.get(url);
return res.data;
} catch (err) {
if (i === attempts - 1) throw err;
}
}
};If the API works ā great.
If it fails ā try again.
If it always fails ā cry.
āļø Step 2āāāMocking Failure āĀ Success
š fetchRetry.test.js
jest.mock('axios');
const axios = require('axios');
const { fetchExpensesWithRetry } = require('./fetchRetry');
test('should retry once and succeed', async () => {
axios.get
.mockRejectedValueOnce(new Error('Network Error'))
.mockResolvedValueOnce({ data: [{ id: 1, amount: 500 }] });
const result = await fetchExpensesWithRetry('/expenses');
expect(axios.get).toHaveBeenCalledTimes(2);
expect(result.length).toBe(1);
});We fake sufferingā¦
so our users donāt have to.
ā ļø Step 3āāāMocking Permanent Failure
Some APIs never want to work.
Like gym membershipsāāāfull of hope, zero results.
test('should fail after max retries', async () => {
axios.get.mockRejectedValue(new Error('Server Down'));
await expect(fetchExpensesWithRetry('/expenses'))
.rejects.toThrow('Server Down');
expect(axios.get).toHaveBeenCalledTimes(3);
});Now your tests donāt just celebrate success.
They respect failure.
š Step 4āāāMocking Slow Responses (Timers + Promises)
Sometimes your API responds so slowly
that you begin reevaluating your career choices.
We simulate that:
jest.useFakeTimers();
axios.get.mockImplementation(() =>
new Promise(resolve => {
setTimeout(() => resolve({ data: [] }), 3000);
})
);
jest.runAllTimers();Three seconds gone in one millisecond.
If only life worked like Jest.
š§© Step 5āāāMocking Weird/Broken Responses
Letās simulate the things that cause dev trauma:
Empty data
axios.get.mockResolvedValue({ data: [] });Null data
axios.get.mockResolvedValue({ data: null });Corrupted JSON
axios.get.mockResolvedValue({ data: "ThisIsNotJSONBro" });Your tests should see all of this.
Because your users definitely will.
ā SUMMARY

Today our Expense Tracker became a warrior.
It learned to survive unpredictable network chaos.
We mastered:
Ā š„ Mocking API failures
Ā š Mocking retries
Ā š¢ Mocking slow responses
Ā š§Ø Mocking corrupted responses
Ā š« Mocking permanent failure
Your tests no longer trust the internet.
They trust YOU.
Next post ā Mocking Permissions, Sensors & Device Behaviors
(This one is MASSIVE for React Native devs.)
Thanks forĀ reading.
If this added value, follow me for more clear and practical posts.
ā Alkesh Jethava