コンテンツにスキップ
Documents for MorningStatusApp
Esc
移動開く⌘Jプレビュー
このページの内容

テスト設計書

概要

MorningStatusApp のテストは Vitest で実行する。 テストコマンド: bun run test


テスト分類

分類 対象 配置場所
ユニットテスト ライブラリ関数・ユーティリティ lib/*.test.ts
コンポーネントテスト React コンポーネント(UI 表示・操作) components/*.test.tsx
ページテスト Next.js ページ(Server Component) app/**/*.test.tsx
API テスト Next.js API Route(GET/PUT) app/api/**/*.test.ts
スクリプトテスト バッチスクリプト(同期処理) scripts/*.test.ts

テストファイル一覧

ライブラリ(lib/

ファイル テスト対象 主なテスト項目
lib/blob.test.ts getMembersFromBlob() Blob フェッチ成功・失敗・バリデーションエラー
lib/releases.test.ts getReleases() Prisma フィールドマッピング・null→undefined 変換・TrackLink→ExternalLink
lib/date.test.ts formatJST() JST 変換・空文字・無効値
lib/sns.test.ts resolveSnsCheck() / hasOfficialSnsSourceMatch() 各 snsCheck 状態の解決・SNS ドメイン一致判定
lib/member-release-linker.test.ts linkMemberToReleases() 在籍期間とリリース日の重複判定・overrides 適用
lib/musicbrainz.test.ts fetchReleaseGroupsByArtist() API 正常取得・レート制限(429)再試行・JSON 解析エラー
lib/release-normalizer.test.ts normalizeReleases() / deduplicateReleases() 正規化・重複排除・releaseDate のスペース処理

コンポーネント(components/

ファイル テスト対象 主なテスト項目
components/MemberCard.test.tsx MemberCard 氏名・世代・ステータス・SNS バッジ・最終更新日の表示
components/MemberDetailView.test.tsx MemberDetailView プロフィール表示・編集フォーム・保存・キャンセル・statusHistory 折りたたみ
components/MemberSelect.test.tsx MemberSelect 検索フィルタ(名前・読みの前方一致)・フィルタ解除

ページ(app/

ファイル テスト対象 主なテスト項目
app/page.test.tsx Home(トップ) メンバー件数・最終更新日・バッチサマリ・isRecentlyUpdated 境界値
app/members/[id]/page.test.tsx MemberDetail メンバー表示・notFound・前後ナビゲーション・関連リリース表示
app/releases/page.test.tsx ReleasesPage フォーマット別グルーピング・データなし表示
app/releases/[id]/page.test.tsx ReleaseDetailPage リリース詳細表示・notFound・関連メンバー表示

API Route(app/api/

ファイル テスト対象 主なテスト項目
app/api/members/route.test.ts GET / PUT /api/members Blob フェッチ・保存成功・MEMBERS_BLOB_URL 未設定エラー・statusHistory 蓄積・上限100件

スクリプト(scripts/

ファイル テスト対象 主なテスト項目
scripts/sync-status.test.ts syncMembers() / fetchMemberStatus() / performSearch() SNS 検索・Web 検索・日本語判定・snsCheck 更新・active フラグ不変・スキップ・曜日制御・ドライラン
scripts/sync-discography.test.ts syncDiscography() MusicBrainz 取得・正規化・Blob 保存・ドライラン
scripts/migrate-to-blob.test.ts migrateToBlob() ローカルファイル読み込み・Blob 書き込み
scripts/patch-official-sns.test.ts patchOfficialSns() officialSns マージ・型変換・mergedCount 0件

テスト実装指針

モックパターン

対象 モック方法
fetch(グローバル) vi.stubGlobal('fetch', vi.fn().mockResolvedValue({...}))
環境変数 vi.stubEnv('VAR_NAME', 'value')
Vercel Blob vi.mock('@vercel/blob', () => ({ put: vi.fn() }))
exa-js(クラス) vi.mock('exa-js', ...) + mockImplementation(function() {...})
Dateのみ偽装 vi.useFakeTimers({ toFake: ['Date'] }) + vi.setSystemTime(...)

fetch モックには必ず ok: true を含めること(省略すると正常系が全失敗する)。

exa-js のようなクラスコンストラクタのモックは function キーワードを使うこと (アロー関数では「is not a constructor」エラーになる)。

クリーンアップ

afterEach(() => {
  vi.unstubAllGlobals();
  vi.unstubAllEnvs();
  vi.useRealTimers();   // useFakeTimers を使った場合
  // vi.restoreAllMocks() はタイマーを戻さないため useRealTimers が別途必要
});

Server Component のテスト

Server Component(async function Page())は render() を使わず直接 await して結果を検証する。

const result = await Home();
const html = JSON.stringify(result);
expect(html).toContain('"isRecentlyUpdated":true');

next/linkLinkJSON.stringify で循環参照エラーになるため vi.mock('next/link', ...) で差し替えること。

曜日依存ロジックのテスト

曜日によって結果が変わるロジック(shouldSyncOG() 等)は Date を固定してテストする。

vi.useFakeTimers({ toFake: ['Date'] });
vi.setSystemTime(new Date('2026-01-05T11:30:00Z')); // 月曜日

再試行ロジックのテスト

setTimeout を含む再試行ループは vi.useFakeTimers() 全面適用 + vi.runAllTimersAsync() で完走させる。


テスト実行

bun run test            # 全テスト実行
bun run test --watch    # ウォッチモード
bun run test path/to/file.test.ts  # 特定ファイルのみ

CI では bun run lint(0 warnings)・bun run type-check も合わせて通過させること。

このページは役に立ちましたか?