Appearance
Metanaka Vitest Rule
このリポジトリで unit test を書く・直す・レビューするときのルール。
対象は app/features/**/*.test.ts と app/shared/**/*.test.ts の Vitest テスト。
基本方針
- テストタイトルは日本語で書く。
it(...)のタイトルには、前提または操作と、期待値の両方を入れる。- 形式は
〜した場合は〜となること、または〜のとき〜することを優先する。 - タイトルだけ読んで「何をしたら、何が保証されるのか」が分かるようにする。
- 1 つの
itは 1 つの振る舞いを検証する。タイトルが長くなりすぎる場合は、テストを分ける。 - 実装手順ではなく、ユーザーや呼び出し元から見た振る舞いを書く。
タイトルの書き方
良い例:
ts
it("有効なルーム設定フォームを送信した場合は API に入力値を渡して成功 result を返すこと", async () => {
// ...
})
it("フォームが不正な場合は validation result を返してフィールドエラーを設定すること", async () => {
// ...
})
it("サーバーエラー後に別の有効なフォームを送信した場合はサーバーエラーキーをクリアすること", async () => {
// ...
})避ける例:
ts
it("posts a valid room setup form", async () => {
// 前提は分かるが、期待値が弱い
})
it("有効なルーム設定フォームを送信する", async () => {
// 操作だけで、何が保証されるか分からない
})
it("server error keys", async () => {
// 前提も期待値も曖昧
})テスト構造
テスト本文は原則として次の順に置く。
- 前提を作る。
- 対象の操作を実行する。
- 期待値を検証する。
明示的な // Arrange、// Act、// Assert コメントは、読みやすさが上がる場合だけ使う。短いテストではコメントより空行で区切る。
小さな変更 PR の review では、今回追加・変更された test を優先して現行ルールへ寄せる。 PR の目的から外れる無関係な既存 test の title や構造違反は、一括修正を求めない。
期待値
- タイトルに書いた期待値は、必ず assertion で直接確認する。
- 回帰テストでは「壊したくない状態変化」をタイトルに含める。
- snapshot だけでは title の期待値が直接確認できない場合がある。重要な contract は
toEqual、toStrictEqual、個別 property の assertion などで直接確認する。 - async の途中状態を検証する場合は、未解決の Promise を放置しない。resolve 関数を握って最後に解決し、対象 Promise を
awaitする。 expect(...).toEqual(...)は、重要な contract が読み取れるように必要十分な粒度で書く。
モックと helper
- 外部境界や依存注入された API は
vi.fn()でよい。 - 外部境界が分離されていないファイルをテストする場合は、先に小さな境界へ切り出せるか検討する。HTTP、Firestore、Firebase Auth、timer、random、現在時刻、ブラウザ API などは、feature composable や adapter の引数、または shared の薄い wrapper に寄せてから mock する。
- 境界を切るときは、業務ロジックから見た入力と出力が分かる最小の interface にする。テストのためだけに大きな service object や汎用 repository を作らない。
- 既存コードの責務がまだ整理されておらず、今回の変更範囲で分離すると影響が大きすぎる場合は、module mock を最小限に使ってよい。その場合も、新規コードでは境界を注入できる形へ寄せる。
- 同じ成功レスポンスや deferred Promise を複数テストで使う場合は、小さな helper に切り出してよい。
- helper 名も期待する意図が分かる名前にする。
例:
ts
const createSuccessfulRoomResponse = () => ({
ok: true,
data: {
roomId: "1b0d6f59-2d62-42f9-920d-0e0f2f7a2c41",
roomCode: "123456",
},
})