유데미-Jest/RTL 강의를 통해 TDD를 학습하던 중 useEffect를 사용하여 데이터를 가져와 state 처리하는 로직을 test 시, 아래와 같이 not wrapped in act
error가 발생되었다.
useEffect(() => {
async function fetchData() {
await axios
.get(`http://localhost:3030/${optionType}`)
.then((response) => {
setItems(response.data);
})
.catch(
() => {} //
);
}
fetchData();
});
it("check initial condition of Options that optionType is toppings", async () => {
const totalScoopsPrice = await screen.findByText(/toppings total: /i);
expect(totalScoopsPrice).toHaveTextContent("$0.00");
});
});
위의 해당하는 오류인 not wrapped in act...
나
비슷한 오류인 can't perform a React state update on an unmounted component.
는
일부 비동기 상태 업데이트가 완료되기 전에 테스트 함수가 종료되어서 그렇다.
test code에서의 assertion(expect구문)이 완료되고 해당 함수가 더이상 해야할 게 없기때문에 종료된다. 그러면서 Testing Library에서 컴포넌트를 언마운트시킨다.
그 동안에도 네트워크 호출은 완료되지 않고 테스트 종료,즉 컴포넌트 언마운트 후 반환된다.
따라서 경합 조건(race condition)
이 발생하여 not wrapped in act
나 can't perform a React state update on an unmount component
등의 오류가 일어나는 것이다.
해당 경합 조건(네트워크 호출이 완료되기 전 컴포넌트가 언마운트 되는 형상)을 해결 위해, 컴포넌트가 언마운트 될 때, useEffect나 test code에 클린업
과정을 추가해야 한다.
그러므로써 컴포넌트가 언마운트 될때, 네트워크 호출도 취소하여 경합 조건(race condition)
을 제거할 수 있다.
abortController를 통해 네트워크 호출 종료
useEffect(() => {
async function fetchData() {
const controller = new AbortController();
await axios
.get(`http://localhost:3030/${optionType}`)
.then((response) => {
setItems(response.data);
})
.catch(
() => {} //
);
//abort axios on component upmount
return () => {
controller.abort();
};
}
fetchData();
});
it("check initial condition of Options that optionType is toppings", async () => {
const { unmount } = render(<Options optionType="toppings" />);
const totalScoopsPrice = await screen.findByText(/toppings total: /i);
expect(totalScoopsPrice).toHaveTextContent("$0.00");
});
});
Reference)
https://ui.toast.com/posts/ko_20201126
https://www.udemy.com/course/jest-testing-library/learn/lecture/35193802#overview
https://testing-library.com/docs/react-testing-library/setup/#skipping-auto-cleanup
https://developer.mozilla.org/ko/docs/Web/API/AbortController