Home
React
🎥 React Testing: Mocking HTTP requests
July 25, 2025
2 min

Table Of Contents

01
🌐 Why Mock HTTP Requests?
02
🛠️ Setting Up MSW in Jest
03
💯 Extra Credit: Make Your Mocking Even Better
04
🧼 Recap: Why Use MSW in React Tests?
05
📋 Reflect and Practice

🧪 Mocking HTTP Requests in React Tests: The MSW Way

When you’re writing tests for a frontend application, one of the biggest questions is:

“How do I test components that make HTTP requests?”

The answer depends on the kind of test you’re writing. For end-to-end (E2E) tests, it’s ideal to interact with a real backend or a mocked backend running in the background. But for unit and integration tests (especially those run in Jest), mocking HTTP requests is often the most practical approach.

That’s where Mock Service Worker (MSW) comes in—a powerful library that intercepts network requests in tests and returns mock responses, just like a real server would.

Let’s dive into how and why to use MSW to mock fetch in your Jest tests.


🌐 Why Mock HTTP Requests?

When testing user interactions that involve network requests (e.g., form submissions, data fetching), it’s important to:

  • ✅ Simulate realistic behavior
  • ✅ Keep tests fast and reliable
  • ✅ Avoid relying on real APIs or external services

While tools like Cypress are perfect for full-blown E2E testing, Jest is better suited for faster unit and integration tests.

So for our React tests, we’ll mock network requests using MSW, ensuring:

  • No need for a real server
  • No flaky network delays
  • High test confidence without losing speed

🛠️ Setting Up MSW in Jest

Imagine a component called <Fetch /> that requests data from /greeting and displays the result.

Here’s how we can test it:

// __tests__/fetch.test.js
import * as React from 'react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { render, waitForElementToBeRemoved, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Fetch from '../fetch'
const server = setupServer(
http.post('/greeting', async ({ request }) => {
const data = await request.json()
const { username, password } = data
return HttpResponse.json({ username: username })
})
)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
test('loads and displays greeting', async () => {
render(<Fetch url="/greeting" />)
await userEvent.click(screen.getByText('Load Greeting'))
await waitForElementToBeRemoved(() => screen.getByText('Loading...'))
expect(screen.getByRole('heading')).toHaveTextContent('hello there')
expect(screen.getByRole('button')).toHaveAttribute('disabled')
})

setupServer creates an in-memory mock server ✅ http.get() defines a mock handler for a GET request to /greetingserver.listen() activates it for tests ✅ waitForElementToBeRemoved waits for loading state to disappear ✅ screen.getByRole interacts just like a user would


💯 Extra Credit: Make Your Mocking Even Better

1. ✅ Reuse Centralized Server Handlers

If you already have a set of reusable MSW handlers (e.g., test/server-handlers.js), reuse them:

import { handlers } from '../test/server-handlers'
const server = setupServer(...handlers)

This allows:

  • Shared mock logic between dev and test
  • Offline-friendly development
  • Faster prototyping with unfinished APIs

📘 MSW was originally created for local development mocks—not just testing!


2. 🚨 Test the Unhappy Path

Don’t forget to test what happens when the user submits invalid input or leaves a field empty.

Example: leave the password field blank in a login form and verify that the error message appears.

await userEvent.type(screen.getByLabelText(/username/i), 'admin')
// Don't type in the password field
await userEvent.click(screen.getByRole('button', { name: /submit/i }))
expect(screen.getByRole('alert')).toHaveTextContent(/password is required/i)

3. 🧪 Use Inline Snapshots

Manually copying error message strings can be a pain. Instead, use inline snapshots:

expect(screen.getByRole('alert').textContent).toMatchInlineSnapshot(
`"Oops, something went wrong!"`,
)

This saves you from hardcoding strings and automatically updates with Jest if the error changes (with your approval).

📚 Snapshot Testing in Jest


4. 🛠 Use One-Off Server Handlers

What if you want to simulate a server crash or random failure only for one test?

Use server.use() with a custom response handler:

server.use(
http.post('/greeting', async () => {
await delay(1000) // Simulate network delay
return HttpResponse.json(
{ message: err_message },
{ status: 500 }
)
})
)

This local override avoids:

  • Cluttering global handlers
  • Breaking other unrelated tests
  • Confusing future readers

🧠 Think of it as “test-local mocking” — focused and isolated.


🧼 Recap: Why Use MSW in React Tests?

BenefitExplanation
🎯 Intercepts real requestsNo need to replace fetch or mess with global mocks
🚀 Fast + reliableWorks offline, no network lag, no port conflicts
🧪 Accurate simulationSimulates both happy and unhappy paths easily
🤝 ReusableShare between development and testing environments
🧠 Encourages good testsPromotes testing what users see—not internal implementation details

📋 Reflect and Practice

Want to lock in what you’ve learned about mocking HTTP requests?

✅ Try using MSW in your own tests ✅ Write tests for both success and failure cases ✅ Refactor your mock server into reusable handlers ✅ Use one-off overrides for focused scenarios

And when you’re ready:

👉 Elaboration & Feedback Form



Tags

#ReactTesting

Share

Related Posts

React 19
React 19: Actions — Async State Handling Made Native
December 05, 2025
2 min
© 2025, All Rights Reserved.
Powered By

Social Media

githublinkedinyoutube