Skip to main content
JavaScript & the browser·Module C8 · Lesson 6
TaskBuild spy() returning a function with .calls = [] and .returnValue. Calling the spy pushes args to .calls and returns .returnValue. Set s.returnValue = 42, call s('a', 'b') twice, log s.calls.length, s.calls[0].join(','), s('x') === 42.

Spies — recording calls

150 XP10 min
Theory

When you need to know how a function called its dependencies

A spy is a fake function that records every call and lets you assert on them later.

function spy() {
  const fn = function (...args) {
    fn.calls.push(args);
    return fn.returnValue;
  };
  fn.calls = [];
  fn.returnValue = undefined;
  return fn;
}

Usage:

const onSave = spy();
onSave.returnValue = "ok";

processForm(formData, onSave);

assert(onSave.calls.length === 1, "save called once");
assertEqual(onSave.calls[0][0].name, "Anna", "first arg was formData");

Why this is enough

Vitest's vi.fn() and Jest's jest.fn() are this exact shape with bells (.mockImplementation, .mockReturnValueOnce, .mockResolvedValue). For 80% of tests, a vanilla spy is plenty.

🔒

Sign up to start coding

Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial — card required, cancel anytime.

Sign up — free trial →

First 10 lessons in each track are free. No card needed for those.

PreviousNext lesson →

Get one Python or web tip a day — by email

Short, hand-written, no spam. Unsubscribe in one click.