React cookbook · Intermediate

Test a data-fetching component with MSW

Write reliable tests for a component that loads data, including loading and error states.

Approach

Mock HTTP with Mock Service Worker so the component's real fetch/TanStack Query code runs. Create a fresh QueryClient per test with retries off, use findBy* queries to wait for async UI, and override handlers per test for error cases.

Solution

import { render, screen } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { afterAll, afterEach, beforeAll, expect, it } from "vitest";
import { UserList } from "./UserList";

const server = setupServer(
  http.get("/api/users", () => HttpResponse.json([{ id: "1", name: "Ada Lovelace" }])),
);
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

function renderWithQuery(ui: React.ReactElement) {
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  return render(<QueryClientProvider client={client}>{ui}</QueryClientProvider>);
}

it("renders users", async () => {
  renderWithQuery(<UserList />);
  expect(screen.getByText(/loading/i)).toBeInTheDocument();
  expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument();
});

it("shows an error message when the API fails", async () => {
  server.use(http.get("/api/users", () => HttpResponse.json({ detail: "boom" }, { status: 500 })));
  renderWithQuery(<UserList />);
  expect(await screen.findByRole("alert")).toHaveTextContent(/couldn't load users/i);
});

Pitfalls

  • A shared QueryClient leaking cached data across tests.
  • Retries making error tests slow.
  • Unhandled requests silently passing — set onUnhandledRequest: 'error'.

Variations

  • Reuse the same MSW handlers in the browser for local development.
  • Playwright component testing for real-browser behavior.

Further reading: MSW: Node.js integration

Reference: https://mswjs.io/docs/integrations/node

More React recipes