この記事は約 5 分で読めます。
筆者プロフィール: ソフトウェアエンジニア。「知った気にならない。いつまでも学び続ける」を信条に、業務と個人開発の両輪で技術を磨いています。AI 駆動開発で複数の個人開発アプリを構築・運用中。
👉 ポートフォリオ: 筆者ホームページ
「新規 page / route を作ったのに、E2E spec を書き忘れて半年後に気づく」 — これを 構造的に防ぐ仕組み を整理します。運用中の SaaS 「たすきば Knowledge Relay」 で実装している pnpm e2e:coverage-check パターンです。
サービスの機能紹介・画面イメージ・コンセプトは公式プロダクトページをご覧ください。
👉 たすきば Knowledge Relay — 公式プロダクトページ
なぜ E2E カバレッジを文書管理するか
たすきばは E2E (End-to-End) テストを Playwright で書いています。カバレッジは、「どの page / API が E2E で覆われているか」 を docs/test/E2E_COVERAGE.md に明文化します。
| ファイル | E2E spec | 状態 |
|---|---|---|
| src/app/(dashboard)/projects/page.tsx | e2e/projects/list.spec.ts | ✓ |
| src/app/api/projects/route.ts | e2e/api/projects.spec.ts | ✓ |
| 目的 | 内容 |
|---|---|
| 書き忘れ防止 | 新規 page / route 追加時の漏れを構造的に防ぐ |
| 状態の可視化 | どのファイルがテスト無しか即座に分かる |
| CI 強制 | 漏れを CI で検知できる |
1. pnpm e2e:coverage-check の仕組み
スクリプト scripts/e2e-coverage-check.ts の挙動:
1. src/app/**/page.tsx と src/app/api/**/route.ts を glob で全列挙
2. docs/test/E2E_COVERAGE.md の表をパース
3. 列挙したファイルが表にあるか確認
4. ないファイルがあれば エラーで exit 1
async function main() {
const pages = await glob('src/app/**/page.tsx');
const routes = await glob('src/app/api/**/route.ts');
const allFiles = [...pages, ...routes];
const coverageDoc = await fs.readFile('docs/test/E2E_COVERAGE.md', 'utf-8');
const documentedFiles = parseTable(coverageDoc).map(row => row.filePath);
const missing = allFiles.filter(f => !documentedFiles.includes(f));
if (missing.length > 0) {
console.error('E2E coverage missing for:');
missing.forEach(f => console.error(` - ${f}`));
process.exit(1);
}
}
CI でこのスクリプトが走り、未記載があれば PR が red になります。
2. 追記漏れで痛い目に遭った実例
PR #372 で実体験した事故。
# ローカルで build + test 全 PASS
pnpm lint # ✓
pnpm tsc # ✓
pnpm test # ✓
pnpm build # ✓
# PR push → CI 走行
pnpm e2e:coverage-check # ✗ 新規 page を文書に追記していない
# CI red
PR がブロックされ、追記してから再 push して通すまで 半日 lost。
当時、私は「lint / tsc / test / build の 4 点セットさえ通せば OK」と思っていました。それは間違い。E2E カバレッジチェックは別 CI ガード。
3. ローカル実行を必須化する運用
docs/test/E2E_COVERAGE.md を必ず更新するルール:
1. 新規 page.tsx / route.ts を作る
2. E2E spec を書く (または書く予定をメモ)
3. docs/test/E2E_COVERAGE.md の表に追記
4. commit 前に pnpm e2e:coverage-check をローカル実行
5. 通ったら commit
Step 4 が重要。CI 待ちで PR が落ちるのは、開発リズムを大きく崩します。
4. CLAUDE.md にも明記
たすきばの CLAUDE.md (Claude Code 運用ガイド) には、コミット前チェックリストとして E2E カバレッジを明記。
## コミット前チェック (毎回必須)
1. 横展開チェック — 同一パターンを検索し漏れなく対応
2. 退行チェック
- 単体テスト (`pnpm test`)
- E2E カバレッジ横展開: 新規 page.tsx / route.ts を追加したら
docs/test/E2E_COVERAGE.md に追記。`pnpm e2e:coverage-check` で gap 検出可
3. デプロイチェック — `pnpm lint` → `pnpm tsc` → `pnpm test`
→ `pnpm e2e:coverage-check` → `pnpm build`
毎回必須にすることで、機械的に漏れを潰します。
5. E2E spec が書けない時の「保留」ステータス
新規 page / route を作ったが、「E2E spec を書く時間がない」「まだ実装が固まっていない」場合もあります。
そんなときは、docs/test/E2E_COVERAGE.md に 「保留」ステータス で記載します。
| ファイル | E2E spec | 状態 |
|---|---|---|
| src/app/(dashboard)/new-feature/page.tsx | - | 🚧 保留 (T-XX) |
| 効果 | 内容 |
|---|---|
| カバレッジチェック pass | リストに存在するため通る |
| 可視化 | 「保留中」が明示される |
| 後追い | 後から拾い上げて E2E を書ける |
完全に書かないより、保留として記録するほうが長期的に追跡可能。
6. なぜここまで仕組み化するか
E2E カバレッジを文書化 + CI 強制までする理由:
| 理由 | 内容 |
|---|---|
| 自分自身が忘れる | 「この page は E2E 書いたっけ?」が頻発 |
| 将来チーム化への投資 | 文書があれば新メンバーが穴を即把握できる |
| リグレッション早期検知 | 後から「気づかなかった」リスクを減らせる |
人間の記憶に頼らずに済む ことが、個人開発の継続性を保つ鍵です。
おわりに
| 仕組み | 効果 |
|---|---|
docs/test/E2E_COVERAGE.md で全 page/route を文書化 |
カバレッジが一覧化 |
pnpm e2e:coverage-check で CI 強制 |
追記漏れを構造的に検知 |
| 保留ステータスでも記載 | 完全 0 を避ける |
| コミット前チェックリストに含める | 機械的に漏れを潰す |
個人開発で品質を維持するために、人間の意思に頼らない仕組み が大切です。
本記事の E2E カバレッジ運用は、運用中の SaaS 「たすきば Knowledge Relay」 で実装しています。
👉 たすきば Knowledge Relay — 公式プロダクトページ