Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

単体、結合、E2E テスト

このページでは、example-based tests がどのリスクを守っているかを整理します。 焦点はテスト数ではなく、検証アプリとして失敗できない境界にどの層のテストを置いているかです。

テスト層の役割

単体テスト

単体テストは、純粋関数、小さな UI component、schema、環境変数 guard、エラー整形の退行検出に使います。

対象:

  • 検証チェック定義と summary logic
  • Lean 生成 vector と照合する verification summary / display / check definition
  • zkVM journal / input commitment / bitmap helper
  • session capability token と Turnstile bypass guard
  • UI component と hooks
  • i18n translation consistency

結合テスト

結合テストは、境界をまたいだ契約が崩れていないかを検査します。

対象:

  • Hono 互換の API route inventory と request / response contract
  • store 実装と finalization state transition
  • verification bundle の public allowlist
  • verifier-service client と STARK receipt status の扱い
  • Lean 生成 vector と照合する input commitment / bitmap Merkle / Rust guest model
  • bitmap proof、bulletin proof、verification run などの session-scoped API

CLI と E2E テスト

CLI と Playwright は、単一関数ではなく利用者フローとしての正しさを見ます。

  • CLI flow: session 作成、投票、集計、検証をブラウザなしで実行する
  • Playwright mock flow: Vite の local-mock build を static Hono server で配信し、主要画面を通す
  • axe smoke: 主要ページの重大な accessibility violation を検出する
  • real zkVM dev flow と real zkVM prod flow: proof contract 変更時に mock だけで完了扱いにしないための重い確認経路

主なコマンド

コマンド目的
pnpm test:runVitest による単体テストと結合テスト
pnpm test:publicpublic snapshot 向けの安全なテスト subset
pnpm test:cli:mockmock zkVM / mock store で CLI voting flow を実行
pnpm test:e2e:mockPlaywright によるブラウザ E2E
pnpm test:e2e:axeaxe accessibility smoke
pnpm test:cli:real-devdevelopment evidence の real zkVM 接続 smoke
pnpm test:cli:real-prod:s0S0 の production STARK proof flow
pnpm formal:verifyLean build / formal vector drift guard
pnpm build:zkvmzkVM guest / host の build
pnpm build:verifier-serviceRust verifier-service の build
pnpm rust:verifier:testverifier-service の Rust tests
pnpm rust:zkvm:testzkVM / contract-core 側の Rust tests

local-proof-development profile の receipt は production STARK proof ではなく、UI/API の回帰検出に有用でも proof soundness を確認したことにはなりません(判定側の扱いは ゲーティングロジック を参照)。

Vitest の ownership

root の pnpm test:run は、workspace manifest と repository tooling metadata から導出した明示的な Vitest project を実行します。 各 apps/*packages/*scripts/、repository tooling scope が自身の test file を所有し、重複した project ownership を許しません。

test environment も scope ごとに固定します。 browser component を持つ @stark-ballot/web だけが jsdom と browser setup を使い、それ以外の workspace と repository tooling は Node environment で実行します。 各 workspace の local test task は狭い確認用で、root の pnpm test:run が repository 全体の単体・結合テスト gate です。 public snapshot では pnpm test:public が公開対象に残した範囲だけを実行します。

mock mode の実行経路

pnpm dev と Playwright mock E2E は、どちらもローカル確認用の mock evidence を使いますが、同じ runtime path ではありません。

経路profile 選択と起動projection の内訳
browser-mock pnpm devVITE_RUNTIME_PROFILE=local-demo で Vite dev server を起動する。server 側も使う場合は .env.localRUNTIME_PROFILE=local-demo を選ぶbrowser projection は browser mock API、Turnstile bypass eligibility、mock proof。server 側は memory store、同期 finalization、local artifact
production ビルド + 静的 Hono(Playwright)pnpm test:e2e:mock / pnpm test:e2e:axe が Playwright の webServer.command から scripts/start-test-server.sh を使い、selector を RUNTIME_PROFILE=static-mock-e2e / VITE_RUNTIME_PROFILE=static-mock-e2e に固定して、NODE_ENV=productionpnpm build:local-mock 後に scripts/dev/static-hono-server.ts を直接起動するbrowser projection は same-origin API と Turnstile bypass eligibility。server projection は file-backed store、mock proof、同期 finalization、local artifact

static-mock-e2e はブラウザ内だけで API を完結させず static Hono server を通るため、pnpm dev より本番配信形に近い経路を確認します。 この分離により、日常の UI 反復は Vite dev server で速く回し、E2E では production-mode の静的 frontend 配信、Hono API handler、session-scoped endpoint、mock zkVM / mock store の結合を確認します。 個別の mock、store、proof、Turnstile flag は runtime selector として使いません。profile の意味論は AWS runtime 境界 を参照してください。 target / reusable な pnpm build:ci artifact は target-aws-async browser profile を選択し、artifact scan で mock API や test-only の Turnstile bypass が混入していないことを確認します。

検査観点

Verified を誤表示しない

このアプリの最優先 invariant は、必要な暗号チェックと整合性チェックが通っていない状態で Verified を表示しないことです。

テストでは次のような状態を fail-closed に扱います。

  • required check が failed
  • required check が not_run / pending / running
  • STARK receipt verification が失敗または未解決
  • unknown check や空の check set
  • excludedSlots > 0
  • public tally と verified tally の不一致

この観点は ゲーティングロジック の実装側の安全網です。

公開 artifact 境界

bundle.zip は第三者検証に必要な公開可能 artifact だけを含みます。 公開してよいものは allowlist で管理し、mode 非依存の保護 4 アーティファクトは配布対象に含めません(一覧と理由は 公開境界 を参照)。

この境界は sync 生成、async container、bundle/report delivery の複数箇所にまたがるため、テストで契約として固定します。

mock zkVM と real zkVM の境界

mock zkVM は UI や API flow の高速な退行検出に使います。 一方で、journal format、input commitment、Image ID、receipt verification contract に触れる変更では、Rust 側や real zkVM 経路を使って TypeScript と Rust の対応を確認します。

コストの違いを前提に、普段は軽い gate を使い、proof contract に触れる変更では重い gate へ進む設計です。

UI と accessibility

Playwright は、ユーザーが実際に触る投票、集計、検証の流れを production-mode の static Hono server 上で確認します。 テスト ID は翻訳文ではなく安定した data-testid を使い、i18n やレイアウト変更に引きずられにくくしています。

CI での位置づけ

CI では、TypeScript の core checks、UI mock E2E、Rust tests、formal checks、public snapshot checks が役割を分けて動きます。 変更領域に応じて必要な gate を選ぶ方針は mock zkVM と real zkVM の境界 と同じです。