react-hooks 테스트하며 알게 된 점

IT공부중·2021년 6월 30일
3

삽질

목록 보기
21/24

@testing-library/react-hooks 와 jest를 사용해서 react-hooks를 test 해보았다.

생각 보다 막히는 곳이 많았다. 그러한 막힌 부분들을 메모해두려고 한다.

infinite Scroll을 테스트 하고 싶었는데,
scrollTop은 변경할 수 있는 값이었지만, scrollHeight나 clientHeight 는 read-only 값이라 변경할 수가 없었다.

그리고 scroll event를 실행시키기가 어려웠다. 해당 문제는 다음과 같이 해결했다. (describe 안의 구문이다.)

jest.useFakeTimers();

  const dispatchScrollEvent = ({
    scrollHeight,
    clientHeight,
    scrollTop,
  }: {
    scrollHeight: number;
    clientHeight: number;
    scrollTop: number;
  }) => {
    
    Object.defineProperty(document.body, 'scrollHeight', {
      value: scrollHeight,
      writable: true,
    });

    Object.defineProperty(document.documentElement, 'clientHeight', {
      value: clientHeight,
      writable: true,
    });

    document.body.scrollTop = scrollTop;
    window.dispatchEvent(new Event('scroll'));
    jest.advanceTimersByTime(500);
  };

document.body의 값들을 바꿀 수 있고, window.dispatchEvent로 event를 발생시켜서 hooks의 useEffect에서 걸어놓은 scroll event를 발생시킬 수 있었다. resize 이벤트 등도 비슷하게 발생시켜 테스트 했다.


reducer를 사용하여 data를 fetch해오는 hooks에서 loading 과 data, error 등을 관리할 수 있게 만들었다. 해당 hooks를 test 하기 위해서, teset의 callback에 asyncawait act 를 사용해야했다. 그렇지 않으면 에러가 발생했다.

it('fetch에 성공하면 state의 data가 바뀌어야한다.', async () => {
    const spy = () => {
      return Promise.resolve({ data: 'test' });
    };

    const { result } = renderHook(() => useAsync<{ test: string }, Error, () => Promise<any>>(spy));

    let [state, fetch, setData] = result.current;
    expect(state).toEqual({
      loading: false,
      data: null,
      error: null,
    });

    await act(async () => {
      await fetch();
    });

    state = result.current[0];
    expect(state).toEqual({
      loading: false,
      data: { data: 'test' },
      error: null,
    });

debounce 등 때문에 setTimeout 후에 적용 되는 값들을 테스트 하기 위해서는
jest.useFakeTimers();
act(() => { jest.advanceTimersByTime(500); });
를 활용하여 테스트를 하였다. 그러면 해당 초 뒤에 rerendering 된 값으로 expect 할수 있었다.

profile
3년차 프론트엔드 개발자 문건우입니다.

0개의 댓글