Vitest と Happy DOM を使用した React コンポーネントのテスト環境構築

## **Vitest と Happy DOM を使用した React コンポーネントのテスト環境構築**

React アプリケーションのテストを `Vitest` と `Happy DOM` を使用して行う手順を、以下の流れで説明します。

---

### **1. 必要なライブラリのインストール**

まず、テストに必要なライブラリをインストールします。

#### **コマンド**
```bash
npm install --save-dev vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event happy-dom
```

#### **ライブラリの説明**
- **`vitest`**: 高速なテストランナー。
- **`@testing-library/react`**: React コンポーネントのテストを支援。
- **`@testing-library/jest-dom`**: DOM に関するカスタムマッチャーを提供。
- **`@testing-library/user-event`**: ユーザー操作（クリックなど）のシミュレーションをサポート。
- **`happy-dom`**: 軽量で高速なブラウザエミュレーション環境。

---

### **2. React コンポーネントの作成**

テスト対象となる簡単なボタンコンポーネントを作成します。

#### **ファイル構成**
```
src/
├── components/
│   ├── ButtonComponent.tsx
├── test/
│   ├── setup.ts
├── vite.config.ts
```

#### **`ButtonComponent.tsx` のコード**
```tsx
import React from 'react';
import { Button } from '@mantine/core';

interface ButtonComponentProps {
  label: string;
  onClick: () => void;
}

const ButtonComponent: React.FC<ButtonComponentProps> = ({ label, onClick }) => {
  return (
    <Button onClick={onClick} data-testid="mantine-button">
      {label}
    </Button>
  );
};

export default ButtonComponent;
```

---

### **3. テストの準備**

#### **テストセットアップファイルの作成**

`setup.ts` ファイルを作成し、テストに必要な設定を記述します。

#### **`setup.ts` のコード**
```typescript
import '@testing-library/jest-dom';

// Happy DOM を使用する際に必要な設定
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(),
    removeListener: vi.fn(),
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
});
```

#### **`vite.config.ts` の設定**

`vite.config.ts` で Happy DOM を使用するように設定します。

```typescript
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'happy-dom', // テスト環境を happy-dom に設定
    globals: true, // describe, it, expect などをグローバルで使用可能にする
    setupFiles: './src/test/setup.ts', // テストセットアップファイルを指定
  },
});
```

---

### **4. テストコードの作成**

`ButtonComponent` をテストするコードを作成します。

#### **ファイル構成**
```
src/
├── components/
│   ├── __tests__/
│   │   ├── ButtonComponent.test.tsx
```

#### **`ButtonComponent.test.tsx` のコード**
```typescript
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MantineProvider } from '@mantine/core';
import ButtonComponent from '../ButtonComponent';

describe('ButtonComponent', () => {
  test('renders with the correct label', () => {
    render(
      <MantineProvider>
        <ButtonComponent label="Click Me" onClick={() => {}} />
      </MantineProvider>
    );

    const buttonElement = screen.getByTestId('mantine-button');
    expect(buttonElement).toBeInTheDocument();
    expect(buttonElement).toHaveTextContent('Click Me');
  });

  test('calls onClick handler when clicked', async () => {
    const handleClick = vi.fn();
    render(
      <MantineProvider>
        <ButtonComponent label="Click Me" onClick={handleClick} />
      </MantineProvider>
    );

    const buttonElement = screen.getByTestId('mantine-button');
    await userEvent.click(buttonElement);

    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});
```

---

### **5. テストの実行**

テストが正常に動作することを確認します。

#### **コマンド**
```bash
npm run test
```

#### **テスト結果**
以下のような出力が表示されれば成功です：

```
 PASS  src/components/__tests__/ButtonComponent.test.tsx
  ButtonComponent
    ✓ renders with the correct label (x ms)
    ✓ calls onClick handler when clicked (x ms)
```

---

### **6. 補足**

#### **Happy DOM と jsdom の違い**
- **`Happy DOM`**:
  - 高速で軽量。
  - 基本的な DOM API のサポート。
  - シンプルなテストに適している。
- **`jsdom`**:
  - DOM API のサポートが充実。
  - より複雑なブラウザシナリオに対応。

#### **選択のポイント**
複雑なブラウザ依存機能（例: `getBoundingClientRect`）が必要ない場合、`Happy DOM` は十分な選択肢です。

---

以上で、`Vitest` と `Happy DOM` を使った React コンポーネントのテスト環境構築とテストの実行手順が完了です！