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 yoursrc
folder with 3 filesbrowser.ts
server.ts
handlers.ts
- In your
app
folder createmsw-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",
});
}),
];
-
browser.ts
setupsmsw
for client side
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
-
server.ts
setupsmsw
for server side
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
-
msw-provider.tsx
enablesmsw
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;
}
- Use
msw-provider
In yourlayout.tsx
like this
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
<MSWProvider>{children}</MSWProvider>
</body>
- To enable
server-side
mocking, add this to yourlayout.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({
...
Let's test msw
on both environments client-side
and server-side
- Create a
client-component.tsx
in yoursrc
mine issrc/components/client-component.tsx
- Make a fetch request to
https://example.com/user
as we described inhandlers.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>;
}
- In your
page.tsx
make a similar request tohttps://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>
);
}
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
Top comments (0)