mcpField
V
vitest

vitest

github.com/claude-dev-suiteテスト・品質4636 回インストール2 日前に更新
リポジトリ

vitest について

JavaScript または TypeScript の開発者向けに、Vitest のテスト作成と保守をまとめたリファレンススキルです。テスト構成、モック、カバレッジ、CI、トラブルシューティングを扱います。

主な機能

  1. 01テストスイートとアサーション
  2. 02関数とモジュールのモック
  3. 03非同期テストのパターン
  4. 04カバレッジと CI の設定
  5. 05テスト構成とトラブルシューティング

活用シーン

  1. 01アプリケーションコードの単体テスト作成
  2. 02API モジュールと関数のモック
  3. 03CI 向けカバレッジレポートの設定

MCP 対応

包括的な Vitest ドキュメントの参照先として `mcp__documentation__fetch_docs` を案内します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill vitest

インストール後、Claude Code で/vitestを入力して読み込まれたか確認します。

同梱ファイルquick-ref/coverage.mdquick-ref/mocking.md

詳細

Vitest コアの知識

深い知識:包括的なドキュメントを参照するには、テクノロジーに vitest を指定して mcp__documentation__fetch_docs を使用してください。

このスキルを使用しない場合

  • E2E テスト - ブラウザーを使ったエンドツーエンドテストには playwright または cypress を使用してください
  • React コンポーネントのテスト - コンポーネントのテストには、このスキルと testing-library を組み合わせてください
  • Jest からの移行 - プロジェクトで Jest を使用している場合は、代わりに jest スキルを使用してください(構文は似ていますが、完全に同じではありません)
  • API 統合テスト - フレームワーク固有の統合テストスキル(spring-boot-integration など)を使用してください

基本的なテスト

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { calculateTotal } from './utils';

describe('calculateTotal', () => {
  it('should sum array of numbers', () => {
    expect(calculateTotal([1, 2, 3])).toBe(6);
  });

  it('should return 0 for empty array', () => {
    expect(calculateTotal([])).toBe(0);
  });
});

マッチャー

// Equality
expect(value).toBe(exact);
expect(value).toEqual(deepEqual);
expect(value).toMatchObject(partial);

// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeDefined();

// Numbers
expect(value).toBeGreaterThan(n);
expect(value).toBeCloseTo(0.3, 5);

// Strings
expect(str).toMatch(/pattern/);
expect(str).toContain('substring');

// Arrays
expect(arr).toContain(item);
expect(arr).toHaveLength(3);

// Errors
expect(() => fn()).toThrow();
expect(() => fn()).toThrowError('message');

モック

// Mock function
const mockFn = vi.fn();
mockFn.mockReturnValue(42);
mockFn.mockResolvedValue({ data: [] });

// Mock module
vi.mock('./api', () => ({
  fetchUsers: vi.fn().mockResolvedValue([])
}));

// Spy
const spy = vi.spyOn(object, 'method');
expect(spy).toHaveBeenCalledWith('arg');

// Reset
vi.clearAllMocks();
vi.resetAllMocks();

非同期テスト

it('should fetch data', async () => {
  const data = await fetchUsers();
  expect(data).toHaveLength(3);
});

it('should reject', async () => {
  await expect(fetchFail()).rejects.toThrow('Error');
});

設定

// vitest.config.ts
export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    coverage: { provider: 'v8', reporter: ['text', 'html'] }
  }
});

本番環境への対応

テストの構成
// Proper test structure
describe('UserService', () => {
  // Setup/teardown at appropriate level
  let service: UserService;
  let mockDb: MockedObject<Database>;

  beforeAll(async () => {
    // Expensive setup once
    await setupTestDatabase();
  });

  beforeEach(() => {
    // Reset state before each test
    mockDb = vi.mocked(new Database());
    service = new UserService(mockDb);
    vi.clearAllMocks();
  });

  afterAll(async () => {
    // Cleanup
    await teardownTestDatabase();
  });

  describe('create', () => {
    it('should create user with valid data', async () => {
      // Arrange
      const input = { name: 'John', email: '[email protected]' };
      mockDb.insert.mockResolvedValue({ id: '1', ...input });

      // Act
      const result = await service.create(input);

      // Assert
      expect(result).toMatchObject(input);
      expect(mockDb.insert).toHaveBeenCalledWith('users', input);
    });

    it('should throw on duplicate email', async () => {
      mockDb.insert.mockRejectedValue(new UniqueConstraintError());
      await expect(service.create(input)).rejects.toThrow('Email already exists');
    });
  });
});
カバレッジの設定
// vitest.config.ts
export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html', 'lcov'],
      exclude: [
        'node_modules/',
        'test/',
        '**/*.d.ts',
        '**/*.config.*',
        '**/types/**',
      ],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 75,
        statements: 80,
      },
    },
  },
});
CI の設定
# GitHub Actions
- name: Run tests
  run: npm run test:ci

- name: Upload coverage
  uses: codecov/codecov-action@v3
  with:
    files: ./coverage/lcov.info
    fail_ci_if_error: true
// package.json scripts
{
  "scripts": {
    "test": "vitest",
    "test:ci": "vitest run --coverage --reporter=junit --outputFile=test-results.xml",
    "test:watch": "vitest --watch"
  }
}
モニタリング指標
指標目標
行カバレッジ> 80%
分岐カバレッジ> 75%
テスト実行時間< 60s
不安定なテストの割合0%
チェックリスト
  • Arrange-Act-Assert パターン
  • 分離されたテスト(共有状態なし)
  • 意味のあるテストの説明
  • カバレッジのしきい値を適用
  • CI/CD との統合
  • テスト内で console.log を使用しない
  • テスト間でモックをリセット
  • 非同期テストで適切に await
  • エッジケースを網羅
  • エラー経路をテスト

アンチパターン

アンチパターン問題点解決策
実装の詳細をテストするリファクタリングでテストが壊れます内部実装ではなく、振る舞いをテストします
テスト間で状態を共有する不安定で、実行順に依存するテストになりますbeforeEach を使用し、セットアップを分離します
根拠のない待機(setTimeout)テストが遅く、不安定になりますwaitFor または非同期ユーティリティを使用します
モックをリセットしない前のテストの影響が次のテストに及びますbeforeEach で vi.clearAllMocks() を呼び出します
プライベートメソッドをテストする実装との結びつきが強くなります公開 API を通じてテストします
巨大なテストを 1 つだけ作成する失敗のデバッグが難しくなりますできれば、テストごとにアサーションを 1 つにします
エラーケースのテストがない本番環境でバグを見逃します正常系とエラー経路の両方をテストします

トラブルシューティングのクイックガイド

問題考えられる原因解決策
"Cannot find module"モックのセットアップ不足vi.mock() のパスが import と一致するか確認します
テストのタイムアウト非同期処理が await されていないすべての非同期処理で await を使用していることを確認します
"Expected 0 calls, received 1"モックがクリアされていないbeforeEach に vi.clearAllMocks() を追加します
不安定なテスト状態の共有またはタイミングセットアップを分離し、setTimeout を避けます
カバレッジが更新されないキャッシュの問題--no-cache フラグを付けて実行します
"TypeError: vi.fn is not a function"インポート不足'vitest' から { vi } をインポートします

参考ドキュメント

コメント