카테고리 없음

React 19 업그레이드 - @testing-library/react-hooks 제거하기

신선아 2025. 4. 25. 00:33

React 19 업그레이드 후, 테스트 코드에서 `ReactDOM.render is not a function` 에러가 발생한 이유와 그 해결 과정을 정리한 글이다.

 

문제 상황

React 18에서 React 19로 업그레이드하며 타입 에러를 대부분 해결했을 때쯤, 테스트 코드에서도 실패 케이스가 발생하는 것을 발견했다. 확인해보니  @testing-library/react-hooks의 renderHook을 사용하는 테스트에서 `ReactDOM.render is not a function`라는 에러 메시지와 함께 실패하고 있었다.

 

문제 원인

React 19에서는 ReactDOM.render가 완전히 삭제되었다. React 18에서 deprecated 처리만 됐었지만, React 19에서는 코드베이스에서 제거되었다.  (관련 문서)

구버전 @testing-library/react-hooks은 내부적으로 훅을 테스트할 때 컴포넌트 트리를 마운트하기 위해 ReactDOM.render를 사용한다. 그래서 React19에서 @testing-library/react-hooks의 renderHook을 사용하는 코드에서 `ReactDOM.render is not a function` 에러가 발생하며 테스트가 실패한 것이다.

 

해결 방법

React 19에서는 @testing-library/react-hooks를 제거하고 @testing-library/react 를 사용해야 한다.

// as-is
import { act, renderHook } from '@testing-library/react-hooks';

// to-be
import { act, renderHook } from '@testing-library/react';

 

React 18 이후 @testing-library/react기존 @testing-library/react-hooks의 주요 기능을 대부분 포함하지만, 일부는 동일하지 않아 몇몇 케이스는 수정이 필요하다. 내가 작업하는 코드베이스에서는 아래 두 가지 케이스가 많아 추가로 정리해보았다. 

waitFor

as-is (@testing-library/react-hooks)

  • renderHook 에서 반환됨
  • 콜백에서 truthy 값을 반환할 때까지 polling
import { renderHook } from '@testing-library/react-hooks';

const { result, waitFor } = renderHook(() => {...})

await waitFor(() => result.current.isSuccess);
expect(result.current.data).toEqual(expectedValue);

to-be (@testing-library/react)

  • @testing-library/react 에서 별도로 import 해서 사용
  • waitFor 콜백함수 내에서 expect를 사용해야함
import { renderHook, waitFor } from '@testing-library/react';


const { result } = renderHook(() => {...})

await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(expectedValue);

 

waitForNextUpdate

as-is (@testing-library/react-hooks)

const { result, waitForNextUpdate } = renderHook(() => useHook());

await waitForNextUpdate();
expect(result.current.somValue).toBe(expectedValue);

to-be (@testing-library/react)

waitForNextUpdate는 renderHook에서 반환되지 않는다. 대신 waitFor를 사용해 대체할 수 있다.

import { waitFor } from '@testing-library/react';

const { result } = renderHook(() => useHook());
await waitFor(() => {
  expect(result.current.someValue).toBe(expectedValue);
});

 

더 자세한 마이그레이션 가이드는 아래 링크에서 확인할 수 있다.

https://github.com/testing-library/react-hooks-testing-library/blob/chore/migration-guide/MIGRATION_GUIDE.md 

 

react-hooks-testing-library/MIGRATION_GUIDE.md at chore/migration-guide · testing-library/react-hooks-testing-library

🐏 Simple and complete React hooks testing utilities that encourage good testing practices. - testing-library/react-hooks-testing-library

github.com

 

마무리하며

버전을 업그레이드할 때 deprecate된 API가 실제로 삭제되기 전까지는 해당 부분에 대해 신경을 잘 못 쓰게 되는 것 같다. 코드베이스가 크다 보니 전면적인 수정은 어렵지만, 업그레이드 가이드 문서를 꼼꼼히 읽고 deprecate 되는 부분에 대해서 팀 내부에 전파하며 미리 대응해둬야겠다는 생각이 들었다.