Vue 3 + Vite プロジェクトでの Vitest によるテスト

Vue 3 + Vite プロジェクトで、Vitest を使用したコンポーネントのテスト方法を解説します。本記事では、Login.vue および Dashboard.vue を対象に、フォームのバリデーション、認証処理、ルーティングを含むテストを実装します。

## 1. 環境セットアップ
### 必要なパッケージのインストール
Vitest と Vue Test Utils をインストールします。
```
npm install --save-dev vitest @vue/test-utils
```
また、Pinia を使用する場合は以下もインストールしてください。
```
npm install pinia
```
## 2. Login.vue コンポーネントのテスト
Login.vue は、メールとパスワードを入力してログインを行うフォームです。
このテストでは、以下の点を確認します。

- フォームが正しくレンダリングされるか

- フォームのバリデーションが機能するか

- ログイン成功時に Dashboard へ遷移するか

- ログイン失敗時にエラーメッセージが表示されるか

### フォームの基本的なレンダリング
```Login.spec.ts
describe('LoginComponent', () => {
  it('ログインフォームを正しくレンダリングする', () => {
    expect(wrapper.find('h2').text()).toBe('ログイン「テスト」');
    expect(wrapper.find('input[type="email"]').exists()).toBe(true);
    expect(wrapper.find('input[type="password"]').exists()).toBe(true);
    expect(wrapper.find('button[type="submit"]').exists()).toBe(true);
  });
});
  ```

  ### フォームバリデーションのテスト
  ```Login.spec.ts
it('メール形式を検証する', async () => {
    const emailInput = wrapper.find('input[type="email"]');
    await emailInput.setValue('invalid-email');
    await emailInput.trigger('blur');
    expect(wrapper.find('.error-message').text()).toContain('有効なメールアドレスを入力');
  });
  ```
  
  ### ログイン成功のテスト
  ```Login.spec.ts
it('成功したログインを処理する', async () => {
    await wrapper.find('input[type="email"]').setValue('test@example.com');
    await wrapper.find('input[type="password"]').setValue('Password123');
    await wrapper.find('form').trigger('submit');
    await new Promise(resolve => setTimeout(resolve, 20));
    expect(router.currentRoute.value.path).toBe('/dashboard');
  });
  ```
  ### ログイン失敗のテスト
  ```Login.spec.ts
it('失敗したログインにエラーメッセージを表示する', async () => {
    await wrapper.find('input[type="email"]').setValue('wrong@example.com');
    await wrapper.find('input[type="password"]').setValue('WrongPass123');
    await wrapper.find('form').trigger('submit');
    await new Promise(resolve => setTimeout(resolve, 20));
    expect(wrapper.find('.error-message').text()).toContain('ログインメールとパスワードは一致しません');
  });
  ```

  ### スナップショットテスト
  ```Login.spec.ts
it('ログイン snapshot', () => {
    expect(wrapper.html()).toMatchSnapshot();
});
  ```
  ## 3. Dashboard.vue コンポーネントのテスト
  Dashboard.vue はログイン後のページで、ユーザー情報を表示し、ログアウト機能を提供します。
  
  ### ログイン後にダッシュボードへ遷移するか
  ```Dashboard.spec.ts
it('ログインが成功した後、ダッシュボードにリダイレクトする', async () => {
    await router.push('/dashboard');
    expect(router.currentRoute.value.path).toBe('/dashboard');
    expect(wrapper.find('h1').text()).toBe('ようこそ、test@example.com さん！');
  });
  ```
  ### ログアウト処理のテスト
  ```Dashboard.spec.ts
it('ログアウトがクリックされた時にログインにリダイレクトする', async () => {
    await wrapper.find('button').trigger('click');
    await new Promise(resolve => setTimeout(resolve, 20));
    expect(router.currentRoute.value.path).toBe('/login');
  });
  ```
  ### スナップショットテスト
  ```Dashboard.spec.ts
it('ダッシュボード snapshot', () => {
    expect(wrapper.html()).toMatchSnapshot();
  });
  ```

  ## 4. テストの実行方法
  ### Vitest の実行コマンド
  Vitest のテストを実行するには、以下のコマンドを使用します。

  ```
  npx vitest
  ```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951101/b3d51951-2f21-4ed3-8a5d-8715e8139fbc.png)

### テスト結果の詳細出力
カバレッジを含めた詳細な出力を表示する場合、以下のコマンドを使用します。
  ```
  npx vitest --coverage
  ```
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951101/2487dab8-06b1-4ffd-8321-4ce91b0c5254.png)

  特定のテストファイルのみを実行したい場合は、次のようにファイル名を指定します。
  ```
  npx vitest Login.spec.ts
  npx vitest Dashboard.spec.ts
  ```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951101/22aeccf9-dfb3-4b98-a5ed-76449ac90ce3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951101/027fa465-ad9c-48f4-b048-80e7412cc676.png)

  ## 5. まとめ
Vitest を使うことで、Vue コンポーネントの振る舞いやルーティング処理を明確にテストでき、保守性・信頼性の高いコードの実現が可能になります。今後の開発やチーム開発において、テストを習慣化する第一歩として、ぜひ活用してみてください！