Home
React
Testing: MSW
Daniel Nguyen
Daniel Nguyen
August 03, 2025
1 min

MSW lets you test API interactions by intercepting network requests and returning controlled responses, without calling real servers.

1. Why Use MSW?

MSW is useful for testing:

  • Successful API requests.
  • Server errors and invalid responses.
  • Loading and empty states.
  • Network failures and retry behavior.

Unlike mocking fetch or Axios directly, MSW intercepts requests at the network boundary. Your application can continue using its normal API client.

2. Setup

Install MSW:

npm install -D msw

Create a test server:

// src/mocks/server.ts
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
export const server = setupServer(
http.post("/greeting", async ({ request }) => {
const { username } = (await request.json()) as {
username: string;
};
return HttpResponse.json({
message: `Hello, ${username}!`,
});
})
);

Configure the test lifecycle:

// src/setupTests.ts
import { beforeAll, afterEach, afterAll } from "vitest";
import { server } from "./mocks/server";
beforeAll(() => {
server.listen({ onUnhandledRequest: "error" });
});
afterEach(() => {
server.resetHandlers();
});
afterAll(() => {
server.close();
});

This setup uses Vitest. With Jest, use Jest’s lifecycle functions instead.

3. Test a Successful Request

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { expect, test } from "vitest";
import Fetch from "../Fetch";
test("loads and displays a greeting", async () => {
const user = userEvent.setup();
render(<Fetch url="/greeting" />);
await user.click(
screen.getByRole("button", { name: /load greeting/i })
);
expect(
await screen.findByRole("heading", {
name: "Hello, Alice!",
})
).toBeInTheDocument();
});

This assumes the component submits { username: "Alice" } and renders the returned message as a heading. Adjust the expected text to match your component’s actual behavior.

4. Test Server Errors

Use server.use() to override a handler for one test:

import { http, HttpResponse } from "msw";
import { server } from "../mocks/server";
test("displays an error when the server fails", async () => {
server.use(
http.post("/greeting", () =>
HttpResponse.json(
{ message: "Something went wrong" },
{ status: 500 }
)
)
);
const user = userEvent.setup();
render(<Fetch url="/greeting" />);
await user.click(
screen.getByRole("button", { name: /load greeting/i })
);
expect(await screen.findByRole("alert")).toHaveTextContent(
/something went wrong/i
);
});

This assumes Fetch displays a suitable error message in an element with role="alert" when the request fails.

server.resetHandlers() restores the initial handlers after each test, preventing overrides from leaking into other tests.

5. Why Is MSW Better?

  • Realistic behavior: Your application uses its normal network client.
  • Deterministic tests: Responses are controlled and repeatable.
  • Easy failure simulation: Test HTTP errors, network failures, and malformed data.
  • Reusable handlers: Share API mocks across component tests and development.

Tags

#ReactTesting

Share

Daniel Nguyen

Daniel Nguyen

Frontend Developer

Frontend developer specializing in React, Next.js, and JavaScript. Writing practical guides on modern web development at Dev98.

Expertise

React
Next.js
JavaScript
TypeScript
Python

Social Media

githublinkedinyoutubewebsite

Related Posts

React Testing
Testing: JSDOM Mocks
August 04, 2025
1 min
Dev98

Dev98

React · Next.js · Web development