What is MSW and how to use it in NextJS

The Teabag Coder - Sep 20 - - Dev Community

What is MSW?

  • MSW is short for mock service worker.
  • A network mocking library for your UI using service worker

- “network mocking” means your code won’t know the different between fake and real APIs

Why use MSW?

Notable benefits:

  • Don't have to create mock data in your frontend code
  • Don't have to go back to modify your frontend code after APIs finished.
  • Can test your UI with various API responses (e.g., success, failure, delays, or specific error codes)
  • Can work in both frontend and backend
  • Can run locally instead of depends on 3rd party tools or live services.

How to use MSW in your NextJS project?

  • Install MSW npm install msw@2.0.14 --save-dev (latest version is having issues)
  • Generate worker script npx msw init public --save
  • Create a folder called mocks inside your src folder with 3 files browser.ts server.ts handlers.ts
  • In your app folder create msw-provider.tsx
  • handlers.ts describes your mock
import { http, HttpResponse } from "msw";
export const handlers = [
    // Intercept "GET https://example.com/user" requests...
    http.get("https://example.com/user", () => {
        // ...and respond to them using this JSON response.
        return HttpResponse.json({
            id: "c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3d",
            firstName: "John",
            lastName: "Maverick",
        });
    }),
];
Enter fullscreen mode Exit fullscreen mode
  • browser.ts setups msw for client side
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
Enter fullscreen mode Exit fullscreen mode
  • server.ts setups msw for server side
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
Enter fullscreen mode Exit fullscreen mode
  • msw-provider.tsx enables msw in your app for client side
"use client";
import { Suspense, use } from "react";
const mockingEnabledPromise =
    typeof window !== "undefined" && process.env.NODE_ENV === "development"
        ? import("../mocks/worker").then(async ({ worker }) => {
                await worker.start();
          })
        : Promise.resolve();

export function MSWProvider({ children }: Readonly<{ children: React.ReactNode }>){
    // If MSW is enabled, we need to wait for the worker to start,
    // so we wrap the children in a Suspense boundary until it's ready.
    return (
        <Suspense fallback={null}>
            <MSWProviderWrapper>{children}</MSWProviderWrapper>
        </Suspense>
    );
}

function MSWProviderWrapper({ children }: Readonly<{ children: React.ReactNode }>){
    use(mockingEnabledPromise);
    return children;
}
Enter fullscreen mode Exit fullscreen mode
  • Use msw-provider In your layout.tsx like this
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
    <MSWProvider>{children}</MSWProvider>
</body>
Enter fullscreen mode Exit fullscreen mode
  • To enable server-side mocking, add this to your layout.tsx
//enable server side mocking
if (process.env.NEXT_RUNTIME === "nodejs") {
    const { server } = require("../mocks/server");
    server.listen();
}
//right before layout function
export default function RootLayout({
...
Enter fullscreen mode Exit fullscreen mode

Let's test msw on both environments client-side and server-side

  • Create a client-component.tsx in your src mine is src/components/client-component.tsx
  • Make a fetch request to https://example.com/user as we described in handlers.ts
"use client";
import { useEffect } from "react";
const getUser = async () => {
    console.log("client-side fetching");
    const response = await fetch("https://example.com/user");
    const json = await response.json();
    console.log(json);
};

export default function ClientComponent() {
    useEffect(() => {
        getUser();
    }, []);
    return <div>client component</div>;
}
Enter fullscreen mode Exit fullscreen mode
  • In your page.tsx make a similar request to https://example.com/user
import ClientComponent from "@/components/client-component";
async function fetchApi() {
    console.log("server fetching");
    const response = await fetch("https://example.com/user");
    const json = await response.json();
    console.log(json);
}

export default async function Home() {
    const user = await fetchApi();
    return (
        <div>
            page
            <ClientComponent />
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

You should see user data being logged in both terminal and browser console.

Thank you for reading this far. Till next time!

Source code: https://github.com/TheTeabagCoder/msw-nextjs-sample

. .
Terabox Video Player