반응형

React test useHref() 오류 해결 방법

React Test 코드를 짜면서 누구나 한 번쯤은 보는 useHref() Link 관련 오류 해결방법에 관한 포스팅입니다. 아직 이 오류를 만나지 않았더라도 해결 방법을 보는 걸 추천드립니다 :0

React Test useHref() 오류 해결
React test useHref() 오류 해결 방법

useHref() 오류 메시지

useHref() may be used only in the context of a <Router> component.

 console.error
    The above error occurred in the <Link> component:

        at LinkWithRef (C:\Users\flyhi\Downloads\codesplain-starter\node_modules\react-router-dom\index.tsx:394:7)
        at div
        at div
        at RepositoriesListItem (C:\Users\flyhi\Downloads\codesplain-starter\src\components\repositories\RepositoriesListItem.js:5:33)

    Consider adding an error boundary to your tree to customize error handling behavior.
    Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

      15 | test('shows a link to the github homepage for this repository', () => {
      16 |   renderComponent();     

11 |     html_url: 'https://github.com/facebook/react',
      12 |   };
    > 13 |   render(<RepositoriesListItem repository={repository} />);
         |         ^
      14 | }
      15 | test('shows a link to the github homepage for this repository', () => {
      16 |   renderComponent();

오류 발생하는 이유

RepositoriesListItem.js 내용을 보면 Link가 있는데, Link 부분에서 테스트 외부 context로 접근하려고 해서 오류 발생. 테스트 환경에서는 Route를 관리하는 설정이 없는데, Route관련 참조를 하려니까 에러가 발생하였습니다. 

        <Link to={`/repositories/${full_name}`} className="text-xl">

오류 해결 방법

RepositoriesListItem.js 코드

//RepositoriesListItem.js
import { Link } from 'react-router-dom';
import FileIcon from '../tree/FileIcon';
import RepositoriesSummary from './RepositoriesSummary';

function RepositoriesListItem({ repository }) {
  const { full_name, language, description, owner, name } = repository;
  return (
    <div className="py-3 border-b flex">
      <FileIcon name={language} className="shrink w-6 pt-1" />
      <div>
        <Link to={`/repositories/${full_name}`} className="text-xl">
          {owner.login}/<span className="font-bold">{name}</span>
        </Link>
        <p className="text-gray-500 italic py-1">{description}</p>
        <RepositoriesSummary repository={repository} />
      </div>
    </div>
  );
}

오류가 발생하는 테스트 코드를 보면 render 부분에 Router관련 component가 없습니다. 

//RepositoriesListItem.test.js
import { render, screen } from '@testing-library/react';
import RepositoriesListItem from './RepositoriesListItem';

function renderComponent() {
  const repository = {
    full_name: 'facebook/react',
    language: 'Javascript',
    description: 'A js library',
    owner: 'facebook',
    name: 'react',
    html_url: 'https://github.com/facebook/react',
  };
  render(<RepositoriesListItem repository={repository} />);
}
test('shows a link to the github homepage for this repository', () => {
  renderComponent();
  
});

해결 방법

MemoryRouter를 import 하여 추가해 주고, test 하려는 component를 <MemoryRouter>로 감싸줍니다. 

import { MemoryRouter } from 'react-router';
  render(
    <MemoryRouter>
      <RepositoriesListItem repository={repository} />
    </MemoryRouter>
  );
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router';
import RepositoriesListItem from './RepositoriesListItem';

function renderComponent() {
  const repository = {
    full_name: 'facebook/react',
    language: 'Javascript',
    description: 'A js library',
    owner: 'facebook',
    name: 'react',
    html_url: 'https://github.com/facebook/react',
  };
  render(
    <MemoryRouter>
      <RepositoriesListItem repository={repository} />
    </MemoryRouter>
  );
}
test('shows a link to the github homepage for this repository', () => {
  renderComponent();
});

그러면 Pass 된 결과를 볼 수 있어요 :)


MemoryRouter?

MemoryRouter는 배열에 내부적으로 위치를 저장한다고 합니다. <BrowserHistory> 및 <HashHistory>와 달리 브라우저의 기록과 같은 외부 소스에 연결되지 않아 테스트와 같은 시나리오에서 쓰인다고 합니다. 

https://reactrouter.com/en/main/router-components/memory-router

 

MemoryRouter v6.14.2

Type declarationdeclare function MemoryRouter( props: MemoryRouterProps ): React.ReactElement; interface MemoryRouterProps { basename?: string; children?: React.ReactNode; initialEntries?: InitialEntry[]; initialIndex?: number; future?: FutureConfig; } A s

reactrouter.com

*udemy React Testing Library and Jest: The Complete Guide를 참고했습니다. 

반응형