Error) `not wrapped in act` of useEffect test

이경섭·2023년 6월 9일
0

RTL/Jest

목록 보기
2/2

유데미-Jest/RTL 강의를 통해 TDD를 학습하던 중 useEffect를 사용하여 데이터를 가져와 state 처리하는 로직을 test 시, 아래와 같이 not wrapped in act error가 발생되었다.

useEffect

  useEffect(() => {
    async function fetchData() {
      await axios
        .get(`http://localhost:3030/${optionType}`)
        .then((response) => {
          setItems(response.data);
        })
        .catch(
          () => {} //
        );
    }
    fetchData();
  });

test code

  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 actcan't perform a React state update on an unmount component 등의 오류가 일어나는 것이다.



해결)

해당 경합 조건(네트워크 호출이 완료되기 전 컴포넌트가 언마운트 되는 형상)을 해결 위해, 컴포넌트가 언마운트 될 때, useEffect나 test code에 클린업 과정을 추가해야 한다.

그러므로써 컴포넌트가 언마운트 될때, 네트워크 호출도 취소하여 경합 조건(race condition)을 제거할 수 있다.

WebAPI - abortController

abortController를 통해 네트워크 호출 종료

useEffect

  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();
  });

test code

  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

0개의 댓글