Tests & verification

All app verification artifacts live under App/Tests/ (ADR-0001). Unit tests that run, plus Integration / E2E / TestDocs boxes, share one parent so the product tree (App/Tokfuel*) stays separate from ops trees (Site / Docs / Scripts). This page carries that layout and how verification is meant to work.

Directory layout

App/Tests/
  UnitTests/          … Swift Testing; what swift test runs
  IntegrationTests/   … integration (placeholder for now)
  E2E/                … end-to-end implementations (not under swift test)
  TestDocs/           … scenario design (documents, not runnable)
  README.md           … parent-directory note

UnitTests

Put headless-checkable logic here. TokfuelTests in Package.swift points at this path; swift test runs it. When you add logic, add tests next to that layer.

Do not write tests that touch real user state under ~/Library/Application Support/Tokfuel.

Line coverage

Snapshot from swift test --enable-code-coverage (2026-08-08). App/ sources only — dependency checkouts excluded.

367 unit tests / 63 suites

App total 2821 / 7800 lines (36.2%)

TokfuelCursor

92% 695/753

TokfuelCore

78% 619/794

TokfuelSettings

74% 168/228

TokfuelBudget

62% 91/146

TokfuelStore

49% 448/910

TokfuelClaude

46% 132/284

TokfuelCodex

43% 15/35

TokfuelAnalytics

29% 17/59

TokfuelUI

15% 602/4021

Tokfuel (app)

6% 34/570

TokfuelUI and the Tokfuel executable skew toward SwiftUI surfaces, so line coverage reads low there. Looks go through ui-preview; headless logic stays in UnitTests.

IntegrationTests

Placeholder for integration tests (README only today). When you add some, use a separate test target or an explicit Package.swift entry — do not dump them into the default UnitTests path.

E2E

Home for end-to-end implementations. Not part of swift test; a separate runner is expected. Do not bring in mobile stacks like Maestro or Appium. Add only what a macOS menu-bar app needs (launch smoke, screen reach) as later Issues require. Scenario design stays canonical in TestDocs.

TestDocs

Scenario design documents — not runnable code. Keep coverage viewpoints here; progress is ticket → implement → update status. Templates, viewpoint IDs, and individual scenarios land in later Issues; the directory box is reserved first.

What UnitTests cover

Store / aggregation & display shaping

  • UsageStore — totals, charts, per-model breakdown, refresh

  • CostChart / CostDisplayMode / Formatting — display shaping and modes

  • MenuBarReadout / MenuBarImage — menu-bar text and rendering

  • RefreshScheduler — idle vs active refresh intervals

Claude (retok)

  • RetokReport — report decoding

  • TranscriptScanner — transcript scanning

  • AdvicePrompt — saving-tip prompts

Cursor / Codex

  • CursorDashboardService / CursorPricing / CursorPricingService — dashboard fetch and price table

  • CursorCostDriver / CursorAdvice — cost estimate and advice

  • CodexCostDriver — cost from Codex CLI sessions

Budget / Settings / other

  • BudgetMonitor — monthly / daily thresholds and once-per-level alerts

  • AppSettings — UserDefaults-backed settings

  • CSVExportService — on-device CSV export

  • UpdateChecker — Releases polling and download boundary

  • HTTPClient / RemoteDiagnosticsPolicy / UsageEventLog — networking and diagnostics policy

  • ScreenshotRenderer — fixture screens for ui-preview

Local verification gates

  • swift test — runs App/Tests/UnitTests. Baseline gate before a PR.

  • swift build -c release — release build close to what Scripts/build.sh packages.

  • bash Scripts/build.sh — installs Tokfuel.app into /Applications and launches it for runtime observation. Do not claim unverified behavior works.

CI

.github/workflows/ci.yml runs unit tests on PRs that touch App/Tokfuel, App/Tests, Package.swift, and related paths. Docs / Site-only changes skip that job. Release packaging is checked via Scripts/build.sh and the distribution flow.

UI preview (screenshots)

Keep new UI visible to reviewers. When you add or change PopoverView, SettingsView, AboutView, or any new standalone View (consent dialogs, alerts, …), update the following in the same PR:

  • ScreenshotRenderer.allScreens() fixtures

  • ORDER / screen_title lists in ui-preview.yml

PRs labeled ui-preview can render those states. Views only reachable through live singletons (network responses, real install paths) need injectable fixtures (see UpdateChecker.preview). Put dialog copy in a SwiftUI view shared by runtime and preview.

How coverage is chosen

Prefer UnitTests for logic that can be checked headlessly. Looks and reachability are covered by ui-preview (VRT-like) and E2E only where needed. Write “what we guarantee” in TestDocs, then implement in UnitTests / IntegrationTests / E2E.