StoryNovember 20, 20253 min read

🧠 Mocking Configurations and Chained Dependencies in Jest — Expense Tracker Edition

Our Expense Tracker is turning into a real grown-up app now.


🧠 Mocking Configurations and Chained Dependencies in Jestā€Šā€”ā€ŠExpense TrackerĀ Edition

Designed by Author usingĀ Figma

Our Expense Tracker is turning into a real grown-up app now.

It’s got multiple files talking to each other, a few third-party libraries, maybe a config file that decides which API URL to hit.

And suddenlyĀ !!!

One innocent change in configuration breaks half the tests.

Welcome to the world of Chained Dependencies.

This is the part where mocking stops being a trickā€Šā€”ā€Šand becomes survival.

šŸ’” TheĀ Problem

Image generated byĀ ChatGPT

Imagine this line buried somewhere deep:

const API_URL = config.get('BASE_URL');
const response = await http.get(API_URL + '/expenses');

You change one setting, and now 23 tests fail because config.get() points to production instead of test.

Congratulations…

You just accidentally DDoSed yourself.

We need a way to mock configs so tests never depend on real environment values.

āš™ļø Step 1ā€Šā€”ā€ŠCreate a ConfigĀ Module

šŸ“ config.js

exports.get = (key) => {
  const values = {
    BASE_URL: 'https://api.example.com',
    CURRENCY: 'INR',
  };
  return values[key];
};

Simple enough.

But if this connects to process.env or remote settings, your tests will get messy fast.

🧪 Step 2ā€Šā€”ā€ŠMock Configuration Values

šŸ“ expenseConfig.test.js

jest.mock('./config', () => ({
  get: jest.fn(),
}));

const { get } = require('./config');
const { fetchExpenses } = require('./expenseApi');

test('should use mocked config for BASE_URL', async () => {
  get.mockReturnValue('https://fake.test/api');
  const result = await fetchExpenses();
  expect(get).toHaveBeenCalledWith('BASE_URL');
  expect(result).toBeDefined();
});

āœ… We just lied beautifullyā€Šā€”ā€Šand safely.

Our tests now believe the API lives on https://fake.test/api, even if the real one is somewhere else.

🧩 Step 3ā€Šā€”ā€ŠMocking Chained Dependencies

Sometimes one module calls another, which calls another, which finally does the thing you care about.

You don’t want to touch all threeā€Šā€”ā€Šyou just want to mock the last one in the chain.

šŸ“ expenseChain.js

const db = require('./db');
exports.saveExpense = async (data) => {
  const user = await db.getUser();
  return db.insertExpense(user.id, data);
};

šŸ“ db.js

exports.getUser = async () => ({ id: 1, name: 'Alkesh' });
exports.insertExpense = async (userId, data) => ({ userId, ...data });

šŸ“ expenseChain.test.js

jest.mock('./db', () => ({
  getUser: jest.fn().mockResolvedValue({ id: 42, name: 'MockUser' }),
  insertExpense: jest.fn().mockResolvedValue({ userId: 42, amount: 500 }),
}));

const { saveExpense } = require('./expenseChain');
const db = require('./db');

test('should mock chained db calls', async () => {
  const result = await saveExpense({ amount: 500 });
  expect(db.getUser).toHaveBeenCalled();
  expect(db.insertExpense).toHaveBeenCalledWith(42, { amount: 500 });
  expect(result.userId).toBe(42);
});

Now we own the entire chain without touching any real database.

That’s like skipping the queue at a cafĆ© because you know the barista. ā˜•

🧠 Step 4ā€Šā€”ā€ŠPartial Mocking AcrossĀ Modules

If you want to keep some real DB logic but mock one function only:

jest.mock('./db', () => {
  const actual = jest.requireActual('./db');
  return {
    ...actual,
    insertExpense: jest.fn().mockResolvedValue({ userId: 1, amount: 0 }),
  };
});

Clean, flexible, and zero drama.

šŸ’¬ Real-World Thought

Every big codebase has ā€œchain painā€ā€Šā€”ā€Šmodules calling modules calling modules.

Without mocks, one tiny function can pull down your whole test suite.

Mocking configs and dependencies lets you sleep peacefully at night.

You are no longer testing the universeā€Šā€”ā€Šjust your own small galaxy. 🌌

āœ… Summary

Image generated byĀ ChatGPT

Today, our Expense Tracker learned how to handle complex relationships like a pro.

It can now:

✨ Mock configuration files safely
Ā āš™ļø Control chained module behavior
 🧩 Partially mock dependencies without breaking the real flow

Our tests are cleaner… faster… and drama-free.

Next stop → we mock data and eventsā€Šā€”ā€Šthe kind of unpredictable chaos that makes tests sweat.

šŸ’¬ Comment which part made you laugh (or cry) the mostā€Šā€”ā€ŠI read them all.

Thanks forĀ reading.

If this added value, follow me for more clear and practical posts.
— Alkesh Jethava

https://alkeshjethava.medium.com/list/jest-made-easy-expense-tracker-edition-91fbfd415b2a