[react] useNavigate testing with testing-library/react

개잼·2023년 12월 24일
0
post-custom-banner

1. 인사

안녕하세요. 이번에는 useNavigate를 testing-library/react로 testing하는 것에 대해 글을 써보려고 합니다.


2. 글 작성 배경

팀 프로젝트를 진행하면서 useNavigate를 testing-library/react로 testing하는 것을 해보려고 했으나, 개발 기간이 6주에 프론트가 혼자라 기존에 TDD를 작성해본 경험이 없는 나로서는 useNavigate testing에 시간을 쏟을 수 없었다.

사실 한 2일 정도 머리를 싸매고 구글링을 해봤으나, 원하는 결과를 못 얻고 결국 시간 작전상 후퇴하였었다.

현재 프로젝트가 끝나고 약간의 여유가 생겨, 시간 작전상 후퇴하였던 문제에 대해 여유롭게 알아보니 원하는 결과를 얻을 수 있었다.

혹시 나 처럼 잘 모르지만 useNavigate에 관하여 testing을 해보고 싶은 사람이 있을 수 있기에 그런 사람의 수고를 덜어주고자 이 글을 작성하게 되었다.


3. 전체 Code

  • App.js
function App() {

  return (
    <div className="App">
      <h1>Main</h1>
    </div>
  );
}

export default App;
  • Detail.js
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function Detail() {
    const navigate = useNavigate();
    
    useEffect(() => {
        navigate('/');
    }, []);


    return(
        <div>
            <h1>Detail</h1>
        </div>
    )
}

export default Detail;
  • RouterWeb.js
import { Route, Routes } from "react-router-dom";
import App from "./App";
import Detail from "./Detail";

function RouterWeb() {
    return (
      <Routes>
        <Route path="/" element={<App />} />
        <Route path="/detail" element={<Detail/>} />
      </Routes>
    )
}

export default RouterWeb;
  • index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import RouterWeb from './RouterWeb';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
     <RouterWeb/>
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
  • Detail.test.js
import { render, screen, waitFor } from '@testing-library/react';
import App from './App';
import { BrowserRouter, MemoryRouter, Routes, Route } from 'react-router-dom';
import Detail from './Detail';

describe("detail to main", () => {
  test('navigate', async () => {
    const route = '/detail'
    render(
      <MemoryRouter initialEntries={[route]}>
        <Routes>
            <Route path="/" element={<App />} />
            <Route path="/detail" element={<Detail/>} />
        </Routes>
      </MemoryRouter>
    
    )
    const detailElement = screen.getByText(/Main/i);
    expect(detailElement).toBeInTheDocument();
  });
});

현재 코드들은 다음과 같이 작성하였습니다.
중요한 것은 Detail.js와 Detail.test.js입니다.
하지만 다른 부분도 염두하면 좋을 거 같아서 올립니다.

먼저 소스코드에 대해 간단히 살펴보겠습니다.


4. Detail.js

import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function Detail() {
    const navigate = useNavigate();
    
    useEffect(() => {
        navigate('/');
    }, []);


    return(
        <div>
            <h1>Detail</h1>
        </div>
    )
}

export default Detail;

보시는 바와 같이 아주 간단한 소스코드입니다.

"/detail"에 접속하면 보이는 Detail.js입니다. 하지만 Detail component를 rendering하면 바로 "/"로 navigate가 되게 작성하였습니다.


5. Detail.test.js

import { render, screen, waitFor } from '@testing-library/react';
import App from './App';
import { BrowserRouter, MemoryRouter, Routes, Route } from 'react-router-dom';
import Detail from './Detail';

describe("detail to main", () => {
  test('navigate', async () => {
    const route = '/detail'
    render(
      <MemoryRouter initialEntries={[route]}>
        <Routes>
            <Route path="/" element={<App />} />
            <Route path="/detail" element={<Detail/>} />
        </Routes>
      </MemoryRouter>
    
    )
    const detailElement = screen.getByText(/Main/i);
    expect(detailElement).toBeInTheDocument();
  });
});

직접적인 test code입니다.
먼저 MemoryRouter에 초기 주소를 지정하였습니다.
초기 주소는 "/detail"로 Detail Component가 처음에 렌더링 되도록 초기주소를 다음과 같이 설정하였습니다.

그럼 현재 Detail Component가 렌더링되면, Detail.js에서 보시는 바와 같이 navigate('/')이 동작할 것입니다.
즉, 이에 따라 App Component가 화면에 렌더링 되는지 확인하면 되겠지요.

이를 확인하기 위해
const detailElement = screen.getByText(/Main/i);
expect(detailElement).toBeInTheDocument(); 를 작성하였습니다.

현재 App.js에는 "Main"이라는 text가 존재하기 때문에
expect를 통해 현재 Main이라는 text가 있는지 확인하고 test가 통과된다면 navigate가 적절히 이루어졌음을 알 수 있겠지요.


6. Result

실행 결과는 다음과 같이 test가 적절하게 이루어졌음을 확인할 수 있었습니다.


7. 소감

코딩하면서 항상 느끼는 거지만 가장 재밌는 순간은 어떤 문제에 대해 스스로 답을 찾아냈을 때 가장 재밌는 것 같습니다. 주변에 물어볼 사람도 없어서 해답을 찾는데 시간은 많이 걸리지만 결국 찾아내는 것이 재밌습니다.

(변태같네)

profile
천천히 나아가는 중
post-custom-banner

0개의 댓글