MSW
MSW(Mock Service Worker)
์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋ฒ API ํธ์ถ์ Mocking(๊ฐ์ง๋ก ๊ตฌํ)ํ ๋ ์ฌ์ฉ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์คํ๋ผ์ธ ์์ ๋ฑ์ ์ง์ํ๊ธฐ ์ํ ์๋น์ค ์์ปค์ ๊ธฐ๋ฅ์ ์ ์ฉํ ํ์ฉํ ๊ฒ
์๋ฒ ์๋ต์ ๊ฐ์ง ๋ฐ์ดํฐ๋ก ๋์ฒดํ์ฌ ์๋ฒ ์์กด์ฑ ์์ด ์ฝ๋๋ฅผ ํ ์คํธํ๊ฑฐ๋ ๊ฐ๋ฐํ ์ ์๋ค.
npm i -D msw
Service Worker
๋ธ๋ผ์ฐ์ ์์ ๋ฉ์ธ ์ค๋ ๋์ ๋ณ๋๋ก ์คํ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ
์ผ๋ฐ์ ์ผ๋ก ๋คํธ์ํฌ ํ๋ก์ ๊ฐ์ ์ญํ ์ด๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ , ์บ์ฑ, ์คํ๋ผ์ธ์ ์ฒ๋ฆฌํ๋๋ฐ ์ฌ์ฉ๋๋ค.
Worker
์น ๋ธ๋ผ์ฐ์์ ๋์ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ ๋ธ๋ผ์ฐ์ ์ ๋ฉ์ธ์ค๋ ๋์์ ์คํ๋๋ค.
์น์์ ์ ๊ณตํ๋ Worker๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ณ๋์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ๊ฐ๋ก๋ง์ง ์๊ณ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ ์ ์๋ค.
๋ฉ์ธ ์ค๋ ๋๋ฅผ non-blocking
ํ๊ธฐ ๋๋ฌธ์ ๋น์ผ ์ฐ์ฐ์ worker ์์ ์คํํ๋ฉด ์ฌ์ฉ์ ๊ฒฝํ์ด ์ข์์ง๋ค.
Window
์ Document
์ ์ ๊ทผํ ์ ์๋ค.
Service Worker๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ
๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ๋๋ ๋ ๋ฆฝ์ ์ธ ์ค๋ ๋
๋คํธ์ํฌ ์์ฒญ ๊ฐ๋ก์ฑ๊ธฐ (ํ๋ก์ ์ญํ )
์บ์ ์ ์ฅ์ ์ ์ด
ํธ์ ์๋ฆผ ์ ๊ณต
๋ฐฑ๊ทธ๋ผ์ด๋ ๋๊ธฐํ ์์ ์ํ
์คํ๋ผ์ธ ์ํฉ์์๋ ์๋ ๊ฐ๋ฅํ ์คํ๋ผ์ธ ๊ธฐ๋ฅ ์ ๊ณต
MSW ํ๊ฒฝ ์ธํ
ํ๊ธฐ
src/mocks/
server.ts
mock server๋ฅผ ๊ตฌ์ฑํ ํ์ผ
import { setupServer } from 'msw/node';
import handlers from './handlers';
const server = setupServer(...handlers);
export default server;
handler.ts
์ฌ์ฉํ api ์คํ์ ์์ฑํ๋ ๊ณณ
๊ฐ๋จํ๊ฒ ํ ์คํธ ๋ฐ ๋ชฉ ๋ฐ์ดํฐ๋ก์ ์ฌ์ฉํ ์ ๋๋ก๋ง ๊ฐ๋ฐํ์. ๋๋ฌด ์น์คํ๋ฉด ๋ฐฑ์๋๋ฅผ ๊ฐ๋ฐํ๋ ๊ฒ์ด๋ ๋งค๋ชฐ๋์ง๋ง์
import { rest } from 'msw';
const BASE_URL = 'http://localhost:3000';
const handlers = [
rest.get(`${BASE_URL}/products`, (req, res, ctx) => {
const products = [
{
category: 'Fruits', price: '$1', stocked: true, name: 'Apple',
},
];
return res(
ctx.status(200),
ctx.json({ products }),
);
}),
];
export default handlers;
MSW with Jest
src/setupTests.ts
import server from './mocks/server';
// ํ
์คํธ ์ ๋ชฉํนํ msw ์๋ฒ์ ์ฐ๊ฒฐ
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// ๊ฐ ํ
์คํธ ํ ๋ค๋ฅธ ํ
์คํธ์ ์ํฅ์ ๋ฏธ์น์ง ์๊ธฐ ์ํด ์ฐ๊ฒฐ๋ ํธ๋ค๋ฌ ์ด๊ธฐํ
afterEach(() => server.resetHandlers());
// ๋ชจ๋ ํ
์คํธ ์๋ฃ ํ ์ฐ๊ฒฐ ๋๊ธฐ
afterAll(() => server.close());
jest.config.js
ํ์ผ์ setupFilesAfterEnv
์์ฑ์ setupTests.ts
ํ์ผ ์ถ๊ฐ
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: [
'@testing-library/jest-dom/extend-expect',
'<rootDir>/src/setupTests.ts', // <-- ์ถ๊ฐ
],
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest', {
jsc: {
parser: {
syntax: 'typescript',
jsx: true,
decorators: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
},
}],
},
};
Testing with MSW
MSW๋ก ์๋ฒ API ์์กด์ฑ์ ๋์ฒดํ์ฌ ํ ์คํ ์ด ๊ฐ๋ฅํ๋ค. Jest๊ฐ ์ ๊ณตํ๋ mock ์์จ๋ ๋จ
npm i -D whatwg-fetch
ํด๋น ํด๋ฆฌํ์ ์ฌ์ฉํ๋ ๊ณณ์์ import 'whatwg-fetch'
๋ฅผ ๋ช
์ํด์ฃผ์ด์ผ ํ๋ค.
msw๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ๊ณณ์์ ํ์ํ๊ธฐ ๋๋ฌธ์ setupTests.ts
์ ๋ช
์ํด์ฃผ์
// src/setupTest.ts
import 'whatwg-fetch';
import server from './mocks/server';
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
polyfill(ํด๋ฆฌํ)
์๋ก์ด ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฒ์ ์ ๊ตฌํ ๋ธ๋ผ์ฐ์ & ๋ ธ๋ ํ๊ฒฝ์์๋ ์ง์ํ ์ ์๋๋ก ๋์์ฃผ๋ ์ฝ๋์กฐ๊ฐ์ด๋ค.
ํน์ ํ๊ฒฝ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฌธ๋ฒ์ ์ง์ํ์ง ์์ ๋ ์ฌ์ฉ๋๋ค.
๊ฐ์ฅ ๋ํ์ ์ผ๋ก ES6์ ์ถ๊ฐ๋ Promise
๋ ie11 ๊ฐ์ ๊ตฌํ ๋ธ๋ผ์ฐ์ ์์ ์ง์ํ์ง ์์ ํด๋ฆฌํ์ ์ฌ์ฉํด์ผ ํ๋ค.
Last updated