Skip to content

Connect MSW ​

MSW intercepts HTTP at the network boundary. Your HttpClient uses the Fetch API, so no code changes are required in the client: point baseUrl (and paths) at URLs your handlers match, and fetch is satisfied by MSW instead of a real server.

This package does not ship MSW; add it to your app or test project:

bash
npm install msw -D
bash
pnpm add msw -D
bash
yarn add msw -D

When it needs ​

  • You want the real HttpClient / fetch path in tests (URL building, headers, formatters, interceptors), not a stubbed client.
  • You want one set of handlers for Node and for the browser (or Cypress / Playwright), with the same URL rules.
  • Your project already uses MSW for HTTP mocking and you want generated endpoints to plug into that setup.

Node.js (setupServer) ​

Use setupServer from msw/node so Node’s globalThis.fetch (and therefore HttpClient) is intercepted in the test process.

  1. Handlers β€” match the full URL the client will request (baseUrl + path, including query if you use it).

mswEndpointHandler wires an endpoint to MSW in one call; see mswEndpointHandler, mswEndpointResponse, and mswPathPattern if you build handlers by hand.

ts
import {
  mswEndpointHandler,
  mswEndpointResponse,
} from "mobx-tanstack-query-api/testing";

// `listFruits`, `createFruit`: your generated endpoints (GET/POST come from `params().method`).
export const handlers = [
  mswEndpointHandler(listFruits, () => ({
    items: ["apple", "banana"],
  })),
  mswEndpointHandler(createFruit, async ({ request }) => {
    const body = (await request.json()) as { name: string };
    return mswEndpointResponse(
      createFruit,
      { id: 1, name: body.name },
      { status: 201 },
    );
  }),
];
  1. Server lifecycle β€” register once per test file or globally via your runner’s setup file (e.g. Vitest setupFiles).
ts
import { setupServer } from "msw/node";
import { afterAll, afterEach, beforeAll } from "vitest";
import { handlers } from "./handlers";

const server = setupServer(...handlers);

beforeAll(() =>
  server.listen({
    onUnhandledRequest: "error", // fail fast if a request has no handler
  }),
);
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
  1. Use your real HttpClient (or generated API module) as in production.
ts
import { HttpClient } from "mobx-tanstack-query-api";

const httpClient = new HttpClient({
  baseUrl: "https://api.example.com",
});

const res = await httpClient.request({
  path: "/api/v1/fruits",
  method: "GET",
  format: "json",
});

expect(res.data).toEqual({ items: ["apple", "banana"] });

Generated endpoints call the same HttpClient.request path, so endpoint.request(...) and EndpointQuery / EndpointMutation flows work as long as the resolved URL matches a handler.

Tips ​

  • Default status codes β€” see testingDefaults; override per response with init.status where applicable.
  • Absolute URLs β€” MSW matches the URL fetch receives. If baseUrl is https://api.example.com and the path is /users/1, the handler pattern should be https://api.example.com/users/1 (or use a path predicate / new URL(request.url) inside the resolver for flexibility).
  • Unhandled requests β€” onUnhandledRequest: "error" catches typos in baseUrl or paths early; relax to "warn" while migrating.
  • Per-test overrides β€” server.use(http.get(...)) after setupServer adds or replaces handlers for a single test; resetHandlers() clears them in afterEach.

Browser and E2E ​

For browser tests (e.g. Cypress, Playwright, or Vite-powered dev), MSW runs in the Service Worker (setupWorker). The same handler URLs apply; ensure the app’s HttpClient baseUrl matches what the worker intercepts (often your dev server origin or a dedicated API host).

When to use MSW vs package Vitest helpers ​

ApproachBest for
MSWExercising the full HttpClient stack (headers, buildUrl, formatters, interceptors), sharing handlers between browser and Node, or teams already standardized on MSW.
Testing helpersFast unit tests without MSW (Vitest-first), typed HttpResponse via mockHttpClientRequest* / mockEndpointRequest*, no global listener.

You can mix both: MSW for integration-style suites and Vitest helpers for narrow endpoint logic.

Further reading ​

Released under the MIT License.