Testing Error Handling in Jest — Expense Tracker Edition
Our Expense Tracker has been doing great so far. It can calculate totals, find the highest expense, and even get averages.
Testing Error Handling in Jest — Expense Tracker Edition

Our Expense Tracker has been doing great so far.
It can calculate totals, find the highest expense, and even get averages.
But what happens when something goes wrong?
What if the list is empty, undefined, or contains values?
In this post, we’ll make our Expense Tracker fail gracefully —
and learn how to use Jest to test those failures.
💡 Why Error Testing Matters
In the real world, users never behave perfectly.
They may:
- Add empty expense lists
- Send strings instead of numbers
- Or worse… forget to send any data at all 😅
If we don’t handle such cases, our app may crash.
That’s why error testing is as important as testing success.
🧱 Step 1 — Add Error Handling to Our Expense Functions
Open your expenseUtils.js file and update it like this:
exports.getTotal = (list) => {
if (!Array.isArray(list)) {
throw new Error('Input must be an array');
}
if (list.length === 0) {
return 0;
}
return list.reduce((a, b) => a + b, 0);
};
exports.getHighestExpense = (list) => {
if (!Array.isArray(list)) {
throw new Error('Input must be an array');
}
if (list.length === 0) {
return 0;
}
return Math.max(...list);
};Now our functions are defensive —
they don’t trust the input blindly.
If something’s wrong, they throw an error immediately.
🧪 Step 2 — Write Jest Tests for Error Cases
Let’s update expenseUtils.test.js to include failure scenarios.
const { getTotal, getHighestExpense } = require('./expenseUtils');
describe('Expense Tracker Error Handling', () => {
test('should throw error if input is not an array', () => {
expect(() => getTotal('not-an-array')).toThrow('Input must be an array');
});
test('should return 0 for empty list in getTotal', () => {
const result = getTotal([]);
expect(result).toBe(0);
});
test('should return 0 for empty list in getHighestExpense', () => {
const result = getHighestExpense([]);
expect(result).toBe(0);
});
});⚙️ Step 3 — Run the Tests
Run:
npm testYou should see:
PASS ./expenseUtils.test.js
Expense Tracker Error Handling
✓ should throw error if input is not an array (2 ms)
✓ should return 0 for empty list in getTotal (1 ms)
✓ should return 0 for empty list in getHighestExpense (1 ms)✅ Great! Our functions now handle both good and bad input safely.
🧠 Step 4 — Understanding .toThrow()
The .toThrow() matcher is how Jest checks if a function throws an error.
Example:
expect(() => getTotal('invalid')).toThrow('Input must be an array');If that function doesn’t throw, or throws a different message, Jest will fail the test.
This makes .toThrow() perfect for testing bad inputs, failed APIs, or invalid states.
⚡ Step 5 — Real-World Value
Error tests might not look exciting…
but they save you hours of debugging later.
When your Expense Tracker grows (and maybe connects to an API or database),
you’ll already have strong test coverage for unexpected data.
Error tests protect you from your future self.
They make your code confident, not just correct.
✅ Summary
In this post, you learned:
- Why testing bad inputs matters
- How to use
.toThrow()in Jest - How to make your Expense Tracker handle empty or invalid data
Next, we’ll step into one of the coolest parts of Jest —
mocking — how to fake data or APIs and still test your code perfectly.
That’s where your testing skills will start feeling pro-level.
💬 Comment what confused you most about testing — I’ll cover it in the next post.
Thanks for reading.
I explain things in simple words so learning stays easy today and even years later.
If this added value, follow me for more clear and practical posts.
— Alkesh Jethava
Previous: #3 Testing Multiple Functions in Jest – Step by Step
Next: #5 Mocking APIs in Jest — Expense Tracker Edition