안녕하세요. 이번에는 useNavigate를 testing-library/react로 testing하는 것에 대해 글을 써보려고 합니다.
팀 프로젝트를 진행하면서 useNavigate를 testing-library/react로 testing하는 것을 해보려고 했으나, 개발 기간이 6주에 프론트가 혼자라 기존에 TDD를 작성해본 경험이 없는 나로서는 useNavigate testing에 시간을 쏟을 수 없었다.
사실 한 2일 정도 머리를 싸매고 구글링을 해봤으나, 원하는 결과를 못 얻고 결국 시간 작전상 후퇴하였었다.
현재 프로젝트가 끝나고 약간의 여유가 생겨, 시간 작전상 후퇴하였던 문제에 대해 여유롭게 알아보니 원하는 결과를 얻을 수 있었다.
혹시 나 처럼 잘 모르지만 useNavigate에 관하여 testing을 해보고 싶은 사람이 있을 수 있기에 그런 사람의 수고를 덜어주고자 이 글을 작성하게 되었다.
function App() {
return (
<div className="App">
<h1>Main</h1>
</div>
);
}
export default App;
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;
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;
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();
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입니다.
하지만 다른 부분도 염두하면 좋을 거 같아서 올립니다.
먼저 소스코드에 대해 간단히 살펴보겠습니다.
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가 되게 작성하였습니다.
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가 적절히 이루어졌음을 알 수 있겠지요.
실행 결과는 다음과 같이 test가 적절하게 이루어졌음을 확인할 수 있었습니다.
코딩하면서 항상 느끼는 거지만 가장 재밌는 순간은 어떤 문제에 대해 스스로 답을 찾아냈을 때 가장 재밌는 것 같습니다. 주변에 물어볼 사람도 없어서 해답을 찾는데 시간은 많이 걸리지만 결국 찾아내는 것이 재밌습니다.
(변태같네)