해당 체크 박스는 서버에서 받아온 데이터를 토대로 갯수가 정해지고, 여러 개의 체크 박스를 테스트 할 예정이므로
waitFor
가 포함된findAllByRole
를 사용.
서버에서 받아온 데이터를 기반으로 화면에 체크박스가 그려지므로 비동기로 처리.async/await
test('fetch option information from server', async () => {
render(<MyComponent />);
// 체크박스 가져오기
const optionCheckboxes = await screen.findAllByRole('checkbox');
expect(optionCheckboxes).toHaveLength(2);
});
구현된 실체가 없으므로 당연 실패..
function MyComponent() {
// .... 생략
const loadItems = async () => {
try {
let response = await axios.get(`http://localhost:5000/products`);
setItems(response.data);
} catch (error) {
setError(true);
}
};
if (error) {
return <ErrorBanner message="에러가 발생했습니다." />;
}
return items.map((item) => (
<>
<input
type="checkbox"
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
id="confirm-checkbox"
/>
<label htmlFor="confirm-checkbox">{item.name}</label>
<br />
<button disabled={!checked} type="submit">
확인
</button>
</>
));
}
export default MyComponent;
Mock Service Worker
백엔드에서 데이터를 가져오는 부분을 테스트하기 위해서는 실제로 서버에 호출하는 end-to-end 테스트를 할 수 있지만
서버에 요청을 보낼 때 그 요청을 가로채서Mock Service Woker
라는 것으로 요청을 처리하고
모의 응답(mocked response)을 보내주는 방법으로도 테스트 진행이 가능하다
MSW
작동 방식두 가지 방법으로 사용할 수 있는데, 하나는 브라우저와 통합하는 방법이고 또 하나는 노드와 통합(Jest 사용하는 테스트 환경)하는 방법이 있다.
그 중 jest 실습 중이므로 노드와 통합(Jest 사용하는 테스트 환경)하는 방법으로 진행.
msw
설치npm install msw --save-dev
# or
yarn add msw --dev
restAPI로 실습했으나 graphql도 가능
req
: 매칭 요청에 대한 정보res
: 모의 응답을 생성하는 기능적 유틸리티ctx
: 모의 응답의 상태 코드, 헤더, 본문 등을 설정하는 데 도움이 되는 함수 그룹포트 5000에서 서버가 작동되어야 에러 없이 진행 가능.. 서버가 없다면 서버가 없다고 에러 발생..
// src > mocks > handlers.js
import { rest } from 'msw';
export const handlers = [
//
rest.get('http://localhost:5000/products', (req, res, ctx) => {
return res(
ctx.json([
{
name: 'America',
imagePath: '/images/america.jpeg',
},
{
name: 'England',
imagePath: '/images/england.jpeg',
},
])
);
}),
rest.get('http://localhost:5000/options', (req, res, ctx) => {
return res(
ctx.json([
{
name: 'Insurance',
},
{
name: 'Dinner',
},
])
);
}),
rest.post('http://localhost:5000/order', (req, res, ctx) => {
let dummyData = [{ orderNumber: 2131234324, price: 2000 }];
return res(ctx.json(dummyData));
}),
];
graphql
샘플 코드// 공식문서의 샘플 코드
import { setupWorker, graphql } from 'msw'
const worker = setupWorker(
graphql.mutation('Login', (req, res, ctx) => {
const { username } = req.variables
return res(
ctx.data({
user: {
username,
firstName: 'John'
}
})
)
})
)
// src > mocks > server.js
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
// mocking server 생성
export const server = setupServer(...handlers)
// src > setupTests.js
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom";
import { server } from "./mocks/server";
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Custom Render
만들기contextAPI 등을 사용할 경우 테스트 케이스에도 context가 필요하기 때문에
컴포넌트 마다 wrapper로 감싸주는 것은 비효율적이므로Custom Render
를 만들어서 테스트 가능
// src > test-utils.js
import { render } from "@testing-library/react";
import { OrderContextProvider } from "./contexts/OrderContext";
const customRender = (ui, options) =>
render(ui, {wrapper: OrderContextProvider, ...options})
export * from '@testing-library/react'
export {customRender as render}
// src > contexts > OrderContext.js
import { createContext } from 'react';
export const OrderContext = createContext();
export function OrderContextProvider(props) {
// ... 생략
return <OrderContext.Provider value={value} {...props} />;
}
// App.js
import { OrderContextProvider } from "./contexts/OrderContext";
function App() {
const [step, setStep] = useState(0);
return (
<OrderContextProvider>
<MyComponent />
</OrderContextProvider>
);
}