StoryNovember 27, 20253 min read

šŸŽ­ Mocking Data and Events in Jest — Expense Tracker Edition

and spy on its own functions like a detective.


šŸŽ­ Mocking Data and Events in Jestā€Šā€”ā€ŠExpense TrackerĀ Edition

Designed by Author usingĀ Figma

Our Expense Tracker has come a long way

it can mock APIs,

tame dependencies,

bend time,

and spy on its own functions like a detective.

But there is one type of chaos still left in the world:
random data and unpredictable events.

The stuff that happens whenever it wants.

Data from users,

Notifications,

Button clicks,

Sensors,

You have 1 new expense! pop-ups,

All the unpredictable messiness of real apps.

Today, we are going to tame that.
We’ll teach Jest how to handle fake data, fake events, and fake scenariosā€Šā€”ā€Šall without touching the real world.

šŸ’” Why Data & Events Are Hard toĀ Test

Image generate byĀ ChatGPT

Real data is messy.

Sometimes it comes too early,

Sometimes too late,

Sometimes not at all.

Sometimes users send you things like "Hello" where you expectedĀ 
{ amount: 500 }.

And events?

They fire whenever they feel like it.
Tap events, input changes, notifications, callbacks firing three times because someone double-clicked too fast.

We cannot trust these things in tests.

We need control.

And control comes from mocking data and events.

🧩 Step 1ā€Šā€”ā€ŠMocking FakeĀ Data

Let’s start simple.

Imagine your Expense Tracker loads a list of expenses from an API and normalizes them:

šŸ“ expenseNormalizer.js

exports.normalizeExpenses = (list) => {
  return list.map(item => ({
    id: item.id,
    amount: Number(item.amount),
    category: item.category || 'Unknown',
  }));
};

Now, instead of relying on real API data, we can mock our own list:

šŸ“ expenseNormalizer.test.js

const { normalizeExpenses } = require('./expenseNormalizer');

test('should normalize expenses correctly', () => {
  const fakeData = [
    { id: 1, amount: "200", category: "Food" },
    { id: 2, amount: 300 }, // no category
  ];

  const result = normalizeExpenses(fakeData);

  expect(result[0].amount).toBe(200);
  expect(result[1].category).toBe('Unknown');
});

No API call.

No waiting.

Just pure, clean, fake data that behaves exactly how we need it to.

If you ever hear a dev saying, ā€œI’ll mock it later,ā€

they actually mean:

ā€œI’ll lie to my code until the truth arrives.ā€

And honestly…

it works.

āš™ļø Step 2ā€Šā€”ā€ŠMocking Events (The FunĀ Part)

Let’s add a tiny event-based feature:

Whenever a user adds a new expense, we fire a listener:

šŸ“ expenseEvents.js

exports.onNewExpense = (listener) => {
  // listener gets called whenever an expense is added
  return listener;
};

And our event trigger:

exports.addExpense = (data, listener) => {
  listener(data);
  return true;
};

Now in our test:

šŸ“ expenseEvents.test.js

const { addExpense } = require('./expenseEvents');

test('should call listener when new expense is added', () => {
  const fakeListener = jest.fn();

  addExpense({ amount: 500 }, fakeListener);

  expect(fakeListener).toHaveBeenCalled();
  expect(fakeListener).toHaveBeenCalledWith({ amount: 500 });
});

Boom šŸ’„ā€Šā€”ā€Ševent tested, no UI needed.

This is how real apps test interactions behind the scenes.

🧠 Step 3ā€Šā€”ā€ŠMocking Randomness

Sometimes functions depend on randomness:

discounts, unique IDs, random numbers, date stamps…

Example:

šŸ“ expenseId.js

exports.generateId = () => Math.floor(Math.random() * 9999);

Test:

const { generateId } = require('./expenseId');

test('should mock random ID', () => {
  jest.spyOn(Math, 'random').mockReturnValue(0.12345);

  const id = generateId();
  expect(id).toBe(1234);

  Math.random.mockRestore();
});

You just controlled randomness.

You are basically a magician now. ✨

🧩 Step 4ā€Šā€”ā€ŠMocking UserĀ Input

Let’s pretend the user enters an expense:

šŸ“ expenseInput.js

exports.parseInput = (input) => ({
  amount: Number(input.amount),
  note: input.note || "",
});

Test:

test('should parse user input', () => {
  const fakeInput = { amount: "400", note: "Snacks" };

  const result = parseInput(fakeInput);

  expect(result.amount).toBe(400);
  expect(result.note).toBe("Snacks");
});

Fake input.

Real confidence.

🧠 Real-World Thought

Mocking data & events is not about taking shortcuts.

It’s about preserving your sanity.

If your tests rely on real user input or actual randomness, they will break randomly too.
Mocking removes uncertainty.

It removes noise.

It gives you focus.

Your tests stop being ā€œtestsā€ and start being predictable simulations of your app’s behavior.

āœ… Summary

Image generate byĀ ChatGPT

Today,

Our Expense Tracker learned to handle fake data, fake events, and fake randomness like a pro.

Now we can:
 ✨ Mock user input
Ā āš™ļø Mock events and listeners
Ā šŸŽ² Control randomness
Ā šŸ’¾ Normalize and test messy data safely

Our tests are cleaner, predictable, and fun to write.

Next stop → we push forward into mocking storage, caching, and persistent data layersā€Šā€”ā€Šthe stuff that usually scares beginners.

šŸ’¬ 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