プログラミング

【Jest/React Testing Library】Reactテスト入門【コンポーネントの振る舞い編】

この記事は約7分で読めます。

初めてReactのテストフレームワークを触るので簡単なテストを行った内容をまとめます。


これまでの学習内容については以下の記事にまとめています。

テストについて

フロントエンドのテストは、アプリケーションの異なる観点で品質を確保するために以下のように分類することができます。

分類確認する観点
単体テスト
(Unit Test)
個々のコンポーネントや関数が正しく動作すること・クリックイベントを正しく処理するか
・値の入力時に、期待通りにステートが更新されるか
結合テスト
(Integration Test)
複数のコンポーネントや機能が連携して正しく動作すること・メモの作成、編集、削除機能が正しく連携して動作するか
・フォームの入力値が正しくステートに反映され、サーバーに送信されるか
エンドツーエンドテスト
(E2E Test)
アプリケーション全体のフローがユーザーの視点で正しく動作すること・ユーザーがフォームに入力し、送信ボタンをクリックした後、メモ一覧が更新されるか

今回は、単体テストをJestReact Testing Libraryを使って行いたいと思います。

JestとReact Testing Library

Jestはテストを行うインフラです。
料理に例えるとコンロやシンクに該当し、これがなければ調理を行うことができないように、Jestはテストを実行するための環境を提供します。

React Testing Library(以降、RTL)はReactコンポーネントをユーザーの視点からテストするためのツールです。
料理に例えるとたこ焼き器やミキサーなど特定の料理を作るためのツールに該当します。

たこ焼き器やミキサーだけでは調理することができず、コンロやシンクを必要とするように、RTL単体ではテストを実行できないためJestの実行環境を使用することでReactのテストを行うことができます。

JestとRTLの導入

TypeScriptを使用したReactプロジェクトにおいてJestとRTLを使用した単体テストを導入するためのステップをまとめます。

なお、以下のテストを理解するためには使用しているプロジェクトのコンポーネントを理解する必要があります。
今回の対象プロジェクトを題材にコンポーネント指向についてまとめたのでぜひ参考にしてください。

JestとRTLのインストール確認

create-react-appを使用している場合、JestとReact Testing Libraryは標準でインストールされています。

Zsh
$ npx jest --version
27.5.1
$ npm ls @testing-library/react
simple-memo-front@0.1.0 /Users/xxxxxxxxxx/Development/simple-memo-frontend
└── @testing-library/react@13.4.0

テストファイルの作成

コンポーネントの振る舞いに関するテスト項目として今回は以下の4つをテストします。

  • MemoContainerコンポーネントがレンダリングされているか
  • NewMemoRowコンポーネントがレンダリングされているか
  • NewMemoRowを押下したら対象のテキストエリアがfocusされるか
  • テキストエリアに入力したらstateに反映されるか
src/__tests__/MemoContainer.test.tsx
import { render, screen, fireEvent } from "@testing-library/react";
import MemoContainer from "../components/MemoContainer/MemoContainer";

describe("MemoContainer", () => {
  beforeEach(() => {
    // 各テスト実行前にレンダリングを実行(記述量が削減できる)
    render(<MemoContainer />);
  });

  // MemoContainerコンポーネントがレンダリングされているかを確認
  test("renders MemoContainer", () => {
    const memoContainer = screen.getByTestId("memo-container");
    expect(memoContainer).toBeInTheDocument();
  });

  // NewMemoRowコンポーネントがレンダリングされているかを確認
  test("renders NewMemoRow", () => {
    const newMemoRow = screen.getByTestId("new-memo-row");
    expect(newMemoRow).toBeInTheDocument();
  });

  // NewMemoRowを押下したら対象のテキストエリアがfocusされるかを確認
  test("click NewMemoRow", () => {
    const newMemoRow = screen.getByTestId("new-memo-row");
    newMemoRow.click();
    const textarea = screen.getByTestId("new-memo-textarea");
    expect(textarea).toHaveFocus();
  });

  // テキストエリアに入力したらstateに反映されるかを確認
  test("input NewMemoRow", () => {
    const newMemoRow = screen.getByTestId("new-memo-row");
    newMemoRow.click();
    const textarea = screen.getByTestId("new-memo-textarea");
    fireEvent.change(textarea, { target: { value: "New memo content" } });
    expect(textarea.value).toBe("New memo content");
  });
});

テストを実行

以下のコマンドでテストを実行します。

Zsh
npm run test

全てのテストで成功していることが分かります。

実行結果
 PASS  src/__tests__/MemoContainer.test.tsx
  MemoContainer
     renders MemoContainer (13 ms)
     renders NewMemoRow (2 ms)
     click NewMemoRow (4 ms)
     input NewMemoRow (4 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        0.478 s, estimated 1 s
Ran all test suites related to changed files.

なお、テストを実行中にファイルを変更した場合は自動的に再テストしてくれます。

まとめ

以上がコンポーネントの振る舞いについてJestReact Testing Libraryを用いてテストを行う方法でした。

クリックや入力などのユーザーのアクションを記述できることで効率的にテストが行えるということを学びました。

ぜひ簡単なテストをやってみてください。

参考文献

【入門】フロントエンドのテスト手法まとめ - Qiita
はじめに自分は2021年に新卒でweb系の開発会社にフロントエンジニアとして入社し2022年で2年目になります。実務ではReact×TypeScriptを利用したフロント周りの開発をメインで行な…
React テストコード(Jest, React Testing Library)の学びと Tips - Qiita
はじめに早いもので2023年も終わりが近づいてきました。皆様はいかがお過ごしでしょうか。毎年アドベントカレンダーの時期になると、今年一年で学び経験した技術の知識を棚卸しするために記事を書いています…
React Testing Libraryの使い方 - Qiita
Robin Wieruch氏によるHow to use React Testing Library Tutorialを著者の許可を得て意訳しました。誤りやより良い表現などがあればご指摘頂けると助か…

コメント