tezvyn:

Difference between jest.fn, jest.spyOn, and jest.mock in React

AI-drafted, machine-checkedSource: jestjs.iointermediate
Difference between jest.fn, jest.spyOn, and jest.mock in React

Tests whether you distinguish Jest's three mocking scopes. Good answers: jest.fn for standalone callbacks; jest.spyOn to observe existing methods; jest.mock to swap entire modules. Red flag: using them interchangeably or saying spyOn replaces modules.

WHAT THIS TESTS: This question tests whether you understand scope, granularity, and side effects across Jest's three primary mocking mechanisms. Senior engineers should know when to replace a single function, observe an existing method, or swap an entire module, and they should understand hoisting and cleanup implications in a React testing environment.

A GOOD ANSWER COVERS: Four distinctions in order. First, jest.fn creates a brand new mock function from scratch, useful for callbacks passed as props or standalone utilities. Second, jest.spyOn wraps an existing method on an object or module, letting you observe calls while usually preserving the original implementation unless you override it. Third, jest.mock operates at the module level, replacing an entire import before the test runs and hoisting above imports so it cannot be called mid-test inside a describe block. Fourth, practical React scenarios: use jest.fn for event handlers like onSubmit to assert they were called with correct arguments; use jest.spyOn to verify that a method on a class instance or a imported named function was invoked without stopping its real behavior; use jest.mock to stub out a heavy child component, a custom hook, or an API client module so the test does not render or fetch real data.

COMMON WRONG ANSWERS: Saying jest.spyOn replaces the entire module or that it permanently mutates the original function across tests. Claiming jest.mock can be called inside a test block to target one function, which ignores hoisting rules. Asserting that jest.fn is the only tool needed because you can just pass it everywhere, which misses module-level isolation. Forgetting to restore or clear mocks between tests, leading to leaked state. Confusing spyOn with mock on default exports, which requires different syntax and understanding of module factories.

LIKELY FOLLOW-UPS: How do you mock a React hook or a child component without breaking prop types? What is the difference between mockReturnValue and mockImplementation, and when would you use one over the other? How do you handle cleanup if a spy overrides the original implementation? Explain how Jest hoisting affects imports and why jest.mock must reference variables outside the factory function. How would you test a module that exports both named and default exports?

ONE CONCRETE EXAMPLE: Imagine a LoginForm component that imports validateEmail from utils and calls an onSubmit prop. Use jest.fn to create the onSubmit prop and assert it receives form data. Use jest.spyOn on the utils module to track validateEmail calls while still running the real validation logic. Use jest.mock to replace the entire analytics module that tracks login events, because you do not want to fire real analytics in unit tests and the module is imported at the top of the file.

Source: jestjs.io

Read the original → jestjs.io

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.