Service Worker API를 사용하여 실제 요청을 가로채는 API 모킹 라이브러리 이다.
FrontEnd 개발 단계에서 백엔드 API가 준비되지 않더라도 실제 API 요청을 구현할 수 있고 테스트를 할 경우에도 유용하게 사용할 수 있다.
npm install msw --save-dev
yarn add msw --dev
// src/mocks/handlers.js
import { rest } from "msw";
export const handlers = [
rest.get("http://localhost:3030/scoops", (req, res, ctx) => {
return res(
ctx.json([
{ name: "Chocolate", imagePath: "/images/chocolate.png" },
{ name: "Vanilla", imagePath: "/images/vanilla.png" },
])
);
}),
rest.get("http://localhost:3030/toppings", (req, res, ctx) => {
return res(
ctx.json([
{ name: "Cherries", imagePath: "/images/cherries.png" },
{ name: "M&Ms", imagePath: "/images/m-and-ms.png" },
{ name: "Hot fudge", imagePath: "/images/hot-fudge.png" },
])
);
}),
rest.post("http://localhost:3030/order", (req, res, ctx) => {
return res(ctx.json({ orderNumber: 123455676 }));
// return res(ctx.status(500));
}),
];
지정된 endpoint로 요청시 리턴 값을 지정할 수 있다.
브라우저 환경에서의 요청을 모킹한다.
// src/mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'
// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers)
// index.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser')
worker.start()
}
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
노드 환경에서의 요청을 모킹한다.
// src/mocks/server.js
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
만약 테스트시 Response 값을 변경하고 싶다면 ?
// src/setUptest.js
import "@testing-library/jest-dom";
import { server } from "./mocks/server";
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test("handles error for scoops and toppings routes", async () => {
server.resetHandlers(
rest.get("http://localhost:3030/scoops", (req, res, ctx) =>
res(ctx.status(500))
),
rest.get("http://localhost:3030/toppings", (req, res, ctx) =>
res(ctx.status(500))
)
);
render(<OrderEntry setOrderPhase={jest.fn()} />);
await waitFor(async () => {
const alerts = await screen.findAllByRole("alert");
expect(alerts).toHaveLength(2);
});
});