4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React Router v6 の自動テスト

Last updated at Posted at 2023-04-01

はじめに

この記事では、React Router を利用したWebアプリの自動テスト実装方法について記載していきます。

前提

開発環境は以下の通りです。

  • Windows11
  • VSCode
  • TypeScript 4.9.5
  • React 18.2.0
  • React Router 6.10.0
  • Vite 4.1.0
  • Vitest 0.28.5
  • @testing-library/react 14.0.0
  • jsdom 21.1.0

また、事前に以下の準備をしています。

  1. Vite でプロジェクトファイルを作成
  2. VitestでReact Testing Libraryを使えるように設定

※詳細はそれぞれ別の記事にまとめています。

デフォルトルートのテスト

Route を利用したアプリ起動時のデフォルトのルートのテストをします。

アプリの実装

まず、App コンポーネントを BrowserRouter で囲み、ルーティングができるようにします。

main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

次にルート("/")アクセス時に Home コンポーネントを開くように実装します。

src/pages/Home.tsx
export const Home = () => {
  return <div>You are home</div>;
};
src/App.tsx
import { Route, Routes } from "react-router-dom";
import { Home } from "./pages/Home";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
    </Routes>
  );
}

export default App;

実装できたので、動作確認をします。ローカルサーバーを立ち上げ、ブラウザで http://localhost:3000/ にアクセスすると、Homeページが表示されることを確認できました。
image.png

テストの実装

App コンポーネントをレンダリングし、 「you are home」と表示されることをテストします(アプリ起動時に Home コンポーネントが開くことをテストします)。

src/__tests__/integration/App.test.tsx
import { render, screen } from "@testing-library/react";
import { BrowserRouter } from "react-router-dom";
import { describe, test } from "vitest";
import App from "../../App";

describe("App routing", () => {
  test("default root", () => {
    render(<App />, { wrapper: BrowserRouter });

    // verify page content for default route
    expect(screen.getByText(/you are home/i)).toBeInTheDocument();
  });
});

テストを通すことができました。
image.png

render の第2引数の wrapper は、第1引数のコンポーネント(コンテナ)を BrowserRouter でラップするために追加しています。アプリ側のコードでは、AppBrowserRouter でラップしているので、テストコードでも同様にラップする必要があります。ラップしないと、エラーが発生します。
image.png
なお、第2引数ではなく、第1引数でラップすることも可能です。

src/__tests__/integration/App.test.tsx
render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

リンクのテスト

Link を利用したページ上のリンクをクリックした際のページ遷移のテストをします。

アプリの実装

まず、遷移先のページである About コンポーネントを作成し、ルーティングに追加します。

src/pages/Home.tsx
export const About = () => {
  return <div>You are on the about page</div>;
};
src/App.tsx
import { Route, Routes } from "react-router-dom";
import { About } from "./pages/About";
import { Home } from "./pages/Home";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
  );
}

export default App;

Home ページ上で、リンクをクリックしたら、About ページに遷移するようにします。

src/pages/Home.tsx
import { Link } from "react-router-dom";

export const Home = () => {
  return (
    <div>
      <div>You are home</div>
      <Link to="/about">About</Link>
    </div>
  );
};

動作確認をします。
ezgif-1-2342bed04c.gif

テストの実装

App コンポーネントをレンダリングした後、リンクをクリックし、その後、ページ上に「you are on the about page」と表示されることをテストします。

src/__tests__/integration/App.test.tsx
test("link", async () => {
  render(<App />, { wrapper: BrowserRouter });
  const user = userEvent.setup();

  // verify page content for expected route after navigating
  await user.click(screen.getByRole("link"));
  expect(screen.getByText(/you are on the about page/i)).toBeInTheDocument();
});

なお、ページ上のリンクが1つだけの場合、上記の書き方でも問題ありませんが、以下のように複数ある場合、エラーになります。

src/pages/Home.tsx
import { Link } from "react-router-dom";

export const Home = () => {
  return (
    <div>
      <div>You are home</div>
      <Link to="/about">About</Link>
      <br />
      <Link to="/form">Form</Link>
    </div>
  );
};

image.png

解決方法は複数ありますが、例えば、第2引数に name を追加することで、クリック対象のリンク(About)を特定させることができます。

src/__tests__/integration/App.test.tsx
test("navigate from root to about by clicking link", async () => {
  render(<App />, { wrapper: BrowserRouter });
  const user = userEvent.setup();

  // verify page content for expected route after navigating
  await user.click(screen.getByRole("link"), { name: "About" });
  expect(screen.getByText(/you are on the about page/i)).toBeInTheDocument();
});

リダイレクトのテスト

Navigate を利用したリダイレクトのテストをします。

アプリの実装

ルート("/")アクセス時に "/home" へリダイレクトするようにします。

src/App.tsx
import { Navigate, Route, Routes } from "react-router-dom";
import { About } from "./pages/About";
import { Home } from "./pages/Home";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Navigate to="/home" />} />
      <Route path="/home" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
  );
}

export default App;

動作確認をします。
ezgif-1-c311ad5c50.gif

テストの実装

App コンポーネントをレンダリングした後、パスが "/home" へ変わっていることを確認します。
まず、テストでパスを確認するため、パス確認用のコンポーネントを作成します。

src/__tests__/libs/LocationDisplay.tsx
import { useLocation } from "react-router-dom";

export const LOCATION_DISPLAY = "location-display";

export const LocationDisplay = () => {
  const location = useLocation();

  return <div data-testid={LOCATION_DISPLAY}>{location.pathname}</div>;
};

次にパス確認用のコンポーネントをテストコード上にレンダリングし、そのコンポーネントのパスが "/home" であることをテストします。

src/__tests__/integration/App.test.tsx
test("default root", () => {
  render(
    <>
      <App />
      <LocationDisplay />
    </>,
    { wrapper: BrowserRouter }
  );

  // verify page content for default route
  expect(screen.getByText(/you are home/i)).toBeInTheDocument();

  // verify page path redirected from root to home
  expect(screen.getByTestId(LOCATION_DISPLAY)).toHaveTextContent("/home");
});

最後に

今回は React Router の RouteLinkNavigate を利用したWebアプリの自動テストを実装しました。React Router にはまだまだたくさんの機能があるので、今後も自動テストを実装できるか確認していければと思っています。

参考

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?