-
Notifications
You must be signed in to change notification settings - Fork 1
Testing
Two layers, both required before merge.
Pure functions are tested with values worked out by hand — app/test/*.test.ts:
-
parse.test.ts—parseBillDetailagainst a synthetic bill fixture (supply/delivery/usage, current charges vs amount due, the carried-balance case). -
series.test.ts—deriveMonthlySeries+trailing12AllIn(e.g. supply $40 ÷ 500 kWh = $0.08; all-in $100 ÷ 500 = $0.20), asserted to many decimals. -
prediction.test.ts— median interval, next-bill date, the near-the-bill check cadence, and the next-bill cost estimate + confidence band. - degree-days, CSV/archive (zip/tgz), and notification format/dedupe also have hand-calculated tests — the new pure helpers all ship a test (kept DB-/Prisma-free so the suite runs without a generated client).
Run them (no DB, no browser, no host Node needed):
docker build --target test -t ngrid-dashboard-test ./app
docker run --rm ngrid-dashboard-testThe test stage in the Dockerfile copies the source + deps and runs vitest run.
When you add pure logic, add a test for it. Prefer a tiny hand-computed fixture over a snapshot — the point is to prove the arithmetic, not to freeze whatever it currently outputs.
GET /api/verify (or Settings → Verify all bills) re-parses every stored bill PDF and
cross-checks the API/stored numbers against it — see Data Accuracy for the full list. This
is what catches "the API gave us a plausible-but-wrong value."
curl -s localhost:3000/api/verify | jq '{ok, total, failed}'
curl -s 'localhost:3000/api/verify?fails=1' | jq # only the failing bills, with detail-
docker run --rm ngrid-dashboard-testis green. - For any change touching numbers:
/api/verifyis green on a real account (paste the summary). - New pure logic ships with a hand-calculated test.
CI runs the unit-test stage on every PR and push and gates the image build on it (the
testjob indocker-publish.yml), alongside amigration-safetyjob — see Releases and CI. Run the suite locally before pushing; CI is the backstop, not a substitute.