Vite と React を用いたコンポーネントテストの設定：Testing Library の導入ガイド

# はじめに
本記事は、Vite を用いて構築された React プロジェクトで Testing Library を活用し、コンポーネントのテスト環境を構築するための備忘録です。

# Testing Library とは
Testing Library は、ユーザーの視点に基づいたテストを容易にするためのJavaScriptテスティングツールです。このライブラリは、ReactやVueなどの人気フレームワークやライブラリに対応し、DOM要素のテストをより直感的で実用的な方法で行うことを可能にします。主にUIコンポーネントの振る舞いをテストする際に使用され、よりクリーンでメンテナンスしやすいテストコードの作成を促進します。[Testing Library 公式サイト](https://testing-library.com/)

https://testing-library.com/

# 環境
使用したNode.jsのバージョン:
```shell
node -v        
v18.12.1
```

# 環境設定

## Viteのプロジェクトの作成
まず、Vite を使って React プロジェクトを作成します。Vite は、高速なフロントエンドのビルドツールであり、React と TypeScript をサポートしています。詳細は [Vite 公式ドキュメント](https://ja.vitejs.dev/) を参照してください。

https://ja.vitejs.dev/

```shell
npm create vite@latest
Need to install the following packages:
  create-vite@5.1.0
Ok to proceed? (y) y
✔ Project name: … ui-test-lesson
✔ Select a framework: › React
✔ Select a variant: › TypeScript

Done. Now run:

  cd ui-test-lesson
  npm install
  npm run dev
```

プロジェクト作成後、必要なライブラリをインストールします。


```shell
cd ui-test-lesson
npm install
```

## testing-libraryの設定
Testing Library とその関連ライブラリを導入します。

- `jest-environment-jsdom`: [Jest で DOM 要素のテストに必要](https://jestjs.io/ja/docs/next/tutorial-jquery)
- `@testing-library/react`: [React で Testing Library を使用するために必要](https://testing-library.com/docs/react-testing-library/intro/)
- `@testing-library/jest-dom`: [Jest のカスタム DOM 要素マッチャーを提供](https://testing-library.com/docs/ecosystem-jest-dom/)
- `@testing-library/user-event`: [イベントのテストに使用](https://testing-library.com/docs/user-event/intro/)


```shell
npm install --save-dev jest @types/jest ts-jest
npm install --save-dev jest-environment-jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
```

Jest の設定ファイルを作成します。
```shell
npx ts-jest config:init
```


作成された jest.config.js は、CommonJSモジュールとESモジュール間の仕様差異に起因するエラーを防ぐために、export default {} の形式で書き換えます。また、テスト環境を設定するために testEnvironment オプションを、先ほどインストールした jest-environment-jsdom に変更します。

```javascript:jest.config.js
export default {
  preset: "ts-jest",
  testEnvironment: "jest-environment-jsdom",
};
```

`tsconfig.json` に `esModuleInterop` を追加し、`types` を設定します。

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true /* 追加する */,
    "types": ["@testing-library/jest-dom"] /* 追加する */
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

```

`jest.setup.ts` をプロジェクト直下に作成し、Testing Library のセットアップを行います。

```typescript:jest.setup.ts
import "@testing-library/jest-dom";
```

`jest.config.js` を更新し、`jest.setup.ts` を読み込むように設定します。


```js:jest.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
  preset: "ts-jest",
  testEnvironment: "jest-environment-jsdom",
  setupFilesAfterEnv: ["./jest.setup.ts"],
};

```

`package.json` にテストコマンドを追加します。

```json:package.json
{
  "scripts": {
    "test": "jest",
    // その他のスクリプト
  }
}
```


# テストの確認

Button コンポーネントのテストを実施してみましょう。
buttonタグがレンダリングされるかと、Buttonコンポーネントに渡しているラベルが表示されているかのテストをします。

```typescript:Button.tsx
interface ButtonProps {
  label: string;
  onClick: () => void;
}

const Button: React.FC<ButtonProps> = ({ label, onClick }) => {
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
};

export default Button;
```

テストコードは下記のようになります。
```typescript: Button.test.tsx
import { render, screen } from "@testing-library/react";
import Button from "./Button";

describe("Button", () => {
  it("buttonタグがレンダリングされる", () => {
    render(<Button label="ボタン" onClick={() => alert("クリック")} />);
    const element = screen.getByRole("button");
    expect(element).toBeInTheDocument(); // buttonタグがレンダリングされる
    expect(element).toHaveTextContent("ボタン"); //ラベルが表示されているか
  });
});

```


テストを実行し、結果を確認します。

```shell
npm test src/components/Button.test.tsx

> ui-test-lesson@0.0.0 test
> jest src/components/Button.test.tsx

 PASS  src/components/Button.test.tsx
  Button
    ✓ buttonタグがレンダリングされる (67 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.057 s
```

テスト成功したのが確認できました！

# おわりに
この記事では、Vite と React を用いたプロジェクトで Testing Library を使ったコンポーネントテスト環境の設定方法についてまとめました。