Mocking Dependencies
Chapter 5 tested components that fetch data, using findBy/waitFor to wait for it — but never addressed where that data actually came from during the test. This chapter closes that gap.
The Problem With Real Network Calls in Tests
A real network call in a test is slow, depends on an external service actually being up, and makes it hard to deliberately trigger error cases (a 500 response, a timeout) on demand. Unit and component tests are supposed to be fast and deterministic — directly the speed argument behind Chapter 1's testing pyramid — and a real network dependency violates both.
Mocking fetch/axios Directly
This works, but couples the test tightly to how the request is made (specifically fetch, or specifically axios) rather than what the request and response actually are. Swapping the underlying HTTP client later means rewriting every test that mocked it this way.
Mock Service Worker (MSW): The Modern Preferred Approach
MSW intercepts requests at the network level rather than mocking the fetch/axios function itself — the component's real request code runs completely unmodified; only the server's response is faked. This is genuinely more realistic, a direct extension of Chapter 3's guiding principle applied to network behavior, and resilient to swapping HTTP libraries later.
The beforeAll/afterAll lifecycle is Chapter 2's setup/teardown hooks, now managing a mock server's lifetime.
Simulating Error Responses
MSW makes deliberately testing error states trivial — override a handler for one test only:
Mocking Timers
Components using setTimeout/setInterval — a debounced search box, a toast that auto-dismisses — would otherwise force tests to actually wait real time, or behave flakily. jest.useFakeTimers() lets a test advance time instantly:
Mocking Context Providers
A component consuming React Context (e.g. useAuth()) needs that context available to render sensibly — wrapping it in a lightweight, test-only provider with preset fake values avoids needing a real login flow or real backend:
A reusable helper like this is worth introducing now — Chapters 8–9's more realistic feature tests will lean on it directly.
Manual fetch/axios Mocking vs. MSW
Manual Mocking
Replaces the HTTP client function itself — couples the test to how requests are made.
MSW (preferred)
Intercepts at the network level — the real request code runs unmodified; only the server's response is faked.
MSW Handlers
Define what a URL returns; override per-test with server.use() for error cases.
Fake Timers
jest.useFakeTimers() + advanceTimersByTime() — instant, deterministic time-based tests.
renderWithProviders
A test-only wrapper supplying fake context values instead of a real provider.
On-Demand Error Simulation
Something a real network call can't easily offer — a genuine testing advantage, not just a workaround.
server.use(...) for one error-case test stays overridden for every test that runs afterward, unless explicitly reset — typically via afterEach(() => server.resetHandlers()). Forgetting this produces confusing failures in later, seemingly unrelated tests that unexpectedly hit the error response meant for a different test entirely. This is Chapter 2's test-isolation principle (resetting shared state in beforeEach), now applying specifically to network mocks.
Coding Challenges
Set up an MSW handler for GET /api/products returning a list of two products, and write a test confirming both product names appear on screen after a ProductList component mounts.
📄 View solutionWrite a test using jest.useFakeTimers() and jest.advanceTimersByTime() for a component that shows "Are you still there?" after 60 seconds of inactivity — confirming the message is absent immediately after render and present after advancing time.
📄 View solutionExplain, with a concrete example, how forgetting server.resetHandlers() in afterEach could cause a test that has nothing to do with errors to fail unexpectedly, if an earlier test in the same file used server.use() to simulate a failed request.
📄 View solutionChapter 6 Quick Reference
- Real network calls in tests are slow, flaky, and can't easily simulate error cases on demand
- Manual fetch/axios mocking — couples tests to how requests are made; works, but fragile to client swaps
- MSW (preferred) — intercepts at the network level; real request code runs unmodified
- server.use(...) — override a handler for one test (e.g. to simulate an error); reset with
server.resetHandlers()in afterEach - jest.useFakeTimers() + advanceTimersByTime() — instant, deterministic testing of setTimeout/setInterval-based behavior
- renderWithProviders — a reusable helper wrapping render() with fake context values instead of real providers
- Forgetting to reset MSW handlers leaks state between tests — the same isolation risk Chapter 2's beforeEach was built to prevent
- Next chapter: Testing Across Frameworks — Vue Test Utils, Angular's TestBed, and Svelte Testing Library