testing について
LobeHub のコントリビューター向けテストガイドです。Web、パッケージ、デスクトップコードのテスト選択や設計、プロジェクト固有の規約を説明します。
主な機能
- 01対象を絞った Vitest コマンド
- 02データベーステストの設定案内
- 03回帰テストの原則
- 04モックとコンポーネントテストの規則
- 05分野別テストガイド
活用シーン
- 01開発中に個別のテストファイルを実行
- 02データベースモデルやリポジトリのテスト追加
- 03実装変更後の失敗テストを評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lobehub/ lobehub --skill testingインストール後、Claude Code で/testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/agent-runtime-e2e.mddb-model-test.mddesktop-controller-test.mdelectron-ipc-test.mdzustand-store-action-test.md詳細
LobeHub テストガイド
クイックリファレンス
コマンド:
# Run specific test file
bunx vitest run --silent='passed-only' '[file-path]'
# Database package (client-db, PGlite — default, no pg_search; BM25 migrations skip themselves)
cd packages/database && bunx vitest run --silent='passed-only' '[file]'
# Database package (server-db, Postgres — BM25/pgvector parity, what CI measures coverage in)
cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only' '[file]'
bun run test は実行しないでください — 3000 件を超えるすべてのテストが実行されます(約 10 分)。
データベースモデル/リポジトリ:
packages/database/src/models/**またはsrc/repositories/**に追加するすべての新しいファイルには、同じ PR 内で同じディレクトリにある__tests__/<name>.test.tsを必ず追加してください。getTestDB()を使って実際の DB に接続し(統合テスト形式)、BM25/全文検索のブロックはdescribe.skipIf(!isServerDB)でガードし、ユーザー分離を必ずテストしてください。セットアップ、スキーマに関する注意点、 クライアント DB とサーバー DB の違いについてはreferences/db-model-test.mdを参照してください。
テストカテゴリ
| カテゴリ | 場所 | 設定 |
|---|---|---|
| Webapp | src/**/*.test.ts(x) | vitest.config.ts |
| Packages | packages/*/**/*.test.ts | packages/*/vitest.config.ts |
| Desktop | apps/desktop/**/*.test.ts | apps/desktop/vitest.config.ts |
基本原則
vi.mockよりvi.spyOnを優先する — より対象を絞りやすく、保守も容易です。ルートの Vitest 設定ではモックが自動的に復元されないため、テストのクリーンアップ時にvi.restoreAllMocks()でスパイを復元してください。- 実装の詳細ではなく、振る舞いをテストする
.github/scripts/配下のネイティブなnode:testによる CI チェックは、アプリの Vitest 検出パスの外に置いてください。テストランナーを併用する場合は、プッシュ前に、意図したランナーと、それを管理する Vitest プロジェクトの両方でファイルが検出されることを確認してください。
- バグ修正にはリグレッションテストを追加する — 修正がなければ失敗し、修正があれば成功するリグレッションテストを追加してください。失敗を簡単に再現できる場合は、まず失敗するテストを書いてください。純粋なスタイル/CSS の修正(セレクター、ホバー、マスク、余白、色)は、スタイルシートのソース文字列との照合が現実的に唯一の検証方法となる場合、テストを省略してください。これは追加する価値のあるリグレッションテストではありません。
- 新しいコンポーネントテストは追加しない — 既存の React コンポーネントテストのみ更新してください。複雑なロジックはフックに切り出し、そこでテストしてください。
UI ライブラリのモック(@lobehub/ui/base-ui)
デフォルト:@lobehub/ui/base-ui はモックせず、実際のコンポーネントをレンダリングしてください。
vitest.config.mts はライブラリ内部の MotionProvider を静的な
スタブ(tests/mocks/lobehubUiMotionProvider.tsx)にリダイレクトするため、アプリレベルの ConfigProvider がなくても base-ui コンポーネントを
テスト内でレンダリングできます。テストで Please wrap your app with <ConfigProvider> (or <MotionProvider>) と表示される場合は、そのリダイレクトが適用されていません
(たとえば、パッケージローカルの vitest 設定など)。すべてのコンポーネントを手動でモックして解決しないでください。
テストで簡略化した DOM が本当に必要な場合は、独自の閉じたファクトリーを書くのではなく、正規のスタブを実際のモジュールに重ねて使用してください(閉じたファクトリーは、ライブラリがコンポーネントのインポートパスを変更するたびに壊れます)。
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
...(await importOriginal<object>()),
...(await import('~base-ui-stubs')).baseUiStubs,
}));
~base-ui-stubs(tests/mocks/baseUiStubs.tsx)は、標準的な aria セマンティクスで ActionIcon / Button /
Text / Tag / Avatar / Alert / toast / confirmModal / createModal をカバーします。アサーションで独自の testid 規約が必要な場合は、ファイルごとのファクトリーを使ってもかまいません。ただし、未知のエクスポートが欠落しないよう、必ず importOriginal をベースに構成してください。
詳細ガイド
特定のテストシナリオについては references/ を参照してください。
- データベースモデルのテスト:
references/db-model-test.md - Electron IPC のテスト:
references/electron-ipc-test.md - Zustand ストアアクションのテスト:
references/zustand-store-action-test.md - エージェントランタイムの E2E テスト:
references/agent-runtime-e2e.md - デスクトップコントローラーのテスト:
references/desktop-controller-test.md
失敗するテストへの対処 — 最適化するか削除するか?
バグではなく実装の変更によってテストが失敗した場合は、むやみに修正する前に評価してください。
維持して修正(テストデータ/アサーションを更新)
- 振る舞いテスト:コードが「何をするか」(出力、副作用、ユーザーに見える動作)を検証するテストです。モックデータの形式や期待値だけを更新します。
- 例:ツールデータの構造が
{ name }から{ function: { name } }に変更された → モックデータを更新 - 例:出力形式が
Current date: YYYY-MM-DDからCurrent date: YYYY-MM-DD (TZ)に変更された → 期待する文字列を更新
- 例:ツールデータの構造が
削除(過剰指定で価値が低い)
- パラメーター転送テスト:関数の内部呼び出し引数を厳密に検証するテスト(例:
expect(internalFn).toHaveBeenCalledWith(expect.objectContaining({ exact params })))です。リファクタリングのたびに失敗し、振る舞いテストでカバーされる内容と重複します。 - 実装に密結合したテスト:コードが内部で「どのように」動作するかを検証し、生成される「結果」を検証しないテストです。より高いレベルのテストで同じ振る舞いをカバーしている場合、低レベルのテストはカバレッジを向上させず、保守コストを増やします。
判断チェックリスト
- 外部から観測可能な振る舞い(API レスポンス、DB 書き込み、レンダリング結果)を検証していますか? → 維持
- 内部の配線(どの関数がどのパラメーターを受け取るか)だけを検証していますか? → 振る舞いテストでカバーされているか確認します。カバーされている場合 → 削除
- 同じ振る舞いが、より高い統合レベルですでにテストされていますか? → 低レベルの重複テストを削除
- 次の通常のリファクタリングで、またテストが失敗する可能性がありますか? → 統合レベルに引き上げるか、削除することを検討
新しいテストを書くとき
- ホワイトボックスアサーション(内部呼び出しを検証)よりも、統合レベルのアサーション(最終出力を検証)を優先します
expect.objectContainingは、安定した公開インターフェースの契約にのみ使用します。リファクタリングで変わる内部パラメーターの形式には使用しません- 内部モジュール間ではなく、境界(DB、ネットワーク、外部サービス)でモックします