はじめに
個人開発で簡単なアプリを作成したりしている中で、いつもユニットテスト作成していなかったので、今回思い立って、JavaScript のユニットテストでよく使われる Jest を使ったテストコードを書いてみたメモです。
コンポーネントのテスト
テスト対象コード
type ButtonProps = {
title: string;
onClick: VoidFunction;
};
export default function Button({ title, onClick }: ButtonProps) {
return (
<button onClick={onClick} className="bg-blue-500 rounded-lg p-4 text-white">
{title}
</button>
);
}
自作のボタンコンポーネントに対するユニットテストを書いてみます。
テストコード
import { fireEvent, render, screen } from "@testing-library/react"; import Button from "../Button"; describe("Buttonコンポーネントテスト", () => { // モック関数を作成 const handleClick = jest.fn(); beforeEach(() => { render(); }); test("タイトルが正しく表示されること", () => { const buttonElement = screen.getByRole("button"); expect(buttonElement).toHaveTextContent("Buttonテスト"); }); test("クリックイベントが行われること", () => { const buttonElement = screen.getByRole("button"); // クリックイベントをシミュレート fireEvent.click(buttonElement); // クリックイベントが呼ばれたことを確認 expect(handleClick).toHaveBeenCalledTimes(1); }); });
- describe は必ず定義しないといけないものではありませんが、正常系や異常系、のようにテストグループを示すなどテストコードの可読性向上に役立つと思います
- beforeEach で各テストごとに実行する前処理を定義しています。ほかにも、beforeAllやafterEach, afterAll などの前処理、後処理が使用できます
- test 関数内に実行するテスト内容を記述していきます
- コンポーネントのユニットテストは、コンポーネントを描画 -> テスト対象要素の取得やイベント発行 -> 結果の検証(expect)が基本の流れとなります
テストを実行すると下記のように表示されます。
npm run test > habbit_tracker@0.1.0 test > jest PASS src/components/__tests__/Button.test.tsx Buttonコンポーネントテスト ✓ タイトルが正しく表示されること (19 ms) ✓ クリックイベントが行われること (4 ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 0.654 s Ran all test suites.
jest 関連でハマった箇所
上記のテストコードで、render 関数でコンポーネントを描画している箇所でエディターのコンパイルエラーが出たり、テスト実行時に、expect 関数の toHaveTextContent が未定義の旨のエラーが出たりして以下の設定系ファイルを用意することでエラー回避できたので、その辺のファイル群も下記に記載します。
もし同じようにテストコードは書いたけどコンパイルエラーが出ている、といったようなエラーに遭遇している方は、下記も試してみてください。
以下いずれもプロジェクトフォルダ直下に配置しました。
babel.config.js
module.exports = { presets: [ "@babel/preset-env", ["@babel/preset-react", { runtime: "automatic" }], // JSXサポートを追加 "@babel/preset-typescript", // TypeScriptサポート ], };
- babelがJSX式を認識するように定義を追加しました。これで render 関数のエラーが解消しました
jest.config.js
module.exports = { testEnvironment: "jest-environment-jsdom", transform: { "^.+\\.(ts|tsx)$": "babel-jest", // TypeScriptファイルをトランスパイル "^.+\\.(js|jsx)$": "babel-jest", // JavaScriptファイルもトランスパイル }, moduleFileExtensions: ["ts", "tsx", "js", "jsx"], // 拡張子を追加 setupFilesAfterEnv: ["/setupTests.ts"], };
setupTests.ts
import "@testing-library/jest-dom";
- describe や expect などのテスト関数を使用できるようにするための import を行っています。
- このファイルを、jest.config.js で読み込むようにすることで、describe を記述した際のエディターのコンパイルエラーが解消しました
終わりに
ユニットテスト避けていましたが、実際やってみるとコードもけっこうわかりやすく書けるし、何よりユニットテストを用意しておくことで安心感が持てました。
今後ユニットテストもセットで書くことを習慣にしていきたいと思います。