公開
テスト方針 — 純ロジック層は 100% ゲート、UI 層は jsdom の振る舞いテスト
engine/lib を純関数に寄せて 100% の閾値を CI で強制し、2026-09-28〜10-01 に全リポジトリで UI 層にも jsdom + Testing Library の振る舞いテストと「実測値の 2 ポイント下」のゲートを足した経緯。書いて見つかったバグも。
個人開発では「テストを書く時間があるなら機能を作りたい」になりがちです。それでも全リポジトリでカバレッジゲートを CI に置いているのは、ゲートがあると設計が純関数に寄り、純関数は後から読んでも分かるからです。方針は 2 段構えです。
1 段目: 純ロジック層を 100% で止める
採点・集計・天体計算・状態遷移のような処理を src/engine や src/lib に閉じ込め、DOM・fs・ネットワークに依存しない純関数にします。そこだけ vitest.config の thresholds を statements / branches / functions / lines すべて 100 にして、CI で下回ったら失敗させます。
- css-atelier / glsl-atelier / snippet-sprint:
src/engine(採点・出題・統計) - lumen-bloom / skydial / somewhere-now:
src/astroなどの天体計算と状態導出。skydial は JPL Horizons・USNO・pvlib-python で生成した fixture と突き合わせる - agent-cockpit:
src/lib。設定ファイルの編集をFileSnapshot → FileEditの純関数にし、書き込みはplanMutationに一本化。これで Electron 抜きの plain Node で 100% を測れる - roba-hud(Swift):
scripts/coverage-gate.shが lib 10 ファイルを行 100% で止める。vitest ではなく llvm-cov
UI や描画層は意図的に外します。snippet-sprint の README にあるとおり、src/render(Three.js/WebGL)は jsdom に WebGL がないので対象外です。
「100% は現実的か」という問いには、純関数に限れば現実的、と答えています。数時間で足りるのは lib 層だけで、UI 層を 80% まで持っていくにはアプリごとに数時間かかりました。
2 段目: UI 層は振る舞いテストで、閾値は実測の 2 ポイント下
2026-09-28 から 10-01 にかけて、ほぼ全リポジトリで UI 層に jsdom + Testing Library の振る舞いテストを足しました。ファイルごとに // @vitest-environment jsdom を宣言し、実際の index.html のマークアップを読み込んで、見える文字・ロール・store・URL の状態を assert します。実装の内部ではなく、ユーザーに見えるものを見ます。
閾値は「計測した値の 2 ポイント下」に置きました。resume の設定コメントには「2026-10-01 計測: components 98.4% / app 99.2% lines。床は 2 ポイント下」とあります。100% にしないのは、UI の分岐には jsdom で到達できないものが残るからで、下がったら気づける床があれば十分です。
書いてみて見つかったバグがいくつかあります。
- css-atelier PR #23: 隠れたキャンバスで 3D 描画が止まらずに残っていた
- ai-primer: locale-switcher で pathname が取れないときのフォールバック不備
- lifeplan-simulator PR #92: 主要画面の操作テストを書いて見つかった不具合を同じ PR で修正
- acro-finder PR #50: UI 層のカバレッジが 50% → 99% になった過程で、next dev の StrictMode でリロード時に状態が消える問題を別 PR(#51)で修正
内容そのものを検証するテスト
コンテンツを持つアプリでは、コードではなく内容を検証するテストも持ちます。service-anatomy の content.test.ts は全記事の ja/en の等価性・出典・スコア範囲を、ai-primer のそれは 40 レッスンと出典 URL の形式を横断検証します。このブログにも同じ型の content.test.ts を置き、frontmatter のスキーマ・日付・参照しているアプリ id の実在・内部リンク切れを CI で止めています。
CI の並び
多くのリポジトリで CI は typecheck → lint → coverage → build の順です。Next 16 では next build が lint を走らせないので、lint のステップを明示しないとどこでも走りません。セキュリティ系は gitleaks と npm audit のゲートを足し、2026-10-03 からは例外リストつきの scripts/audit-gate.mjs に置き換えました(ai-primer・acro-finder・このポートフォリオ)。
テスト件数は 2026-10-05 時点で service-anatomy 1,873・sumai-log 1,581・somewhere-now 683・ai-primer 544・chronoscroll 498・skydial 460・agent-cockpit 421・acro-finder 403 などで、合計は一覧ページの上部に出しています。
参考
- css-atelier PR #23 — UI 層の jsdom テストと隠れたキャンバスのバグ
- acro-finder PR #50 — UI 層のカバレッジ 50% → 99%
- agent-cockpit README(純関数 lib と planMutation)、roba-hud
scripts/coverage-gate.sh - 各リポジトリの
vitest.config.tsのcoverage.thresholds