mike/docs/testing-coverage.md

123 lines
6.3 KiB
Markdown
Raw Permalink Normal View History

# Backend unit-test coverage
The backend has a Vitest unit-test harness over `backend/src/lib/**`. This doc
tracks what is covered, what still needs tests, and how the coverage ratchet
works — so you can pick up a checkbox below and land it as a small PR.
## Running the tests
```bash
cd backend
npm install
npm test # run all unit tests
npm run test:coverage # same, plus the per-file coverage table + floor check
```
Tests live in `backend/src/lib/__tests__/*.test.ts`. Read a couple of the
existing suites first (`access.test.ts`, `userDataCleanup.test.ts`) and match
their conventions: plain in-memory Supabase query mocks (no network, no real
database), one `describe` block per exported function, and tests that assert
current behavior.
## Current coverage (measured 2026-07)
Per-area statement coverage from `npm run test:coverage`:
| Lib area | % statements | Tested? |
| --- | ---: | :---: |
| `lib/safeError.ts` | 100 | ✓ |
| `lib/userDataCleanup.ts` | 100 | ✓ |
| `lib/llm/models.ts` | 100 | ✓ |
| `lib/documentVersions.ts` | 98 | ✓ |
| `lib/chat/citations.ts` | 98 | ✓ |
| `lib/userLookup.ts` | 91 | ✓ |
| `lib/downloadTokens.ts` | 87 | ✓ |
| `lib/chat/types.ts` | 85 | ✓ |
| `lib/access.ts` | 76 | ✓ |
| `lib/storage.ts` | 33 | partial — key/disposition helpers only |
| `lib/userApiKeys.ts` | 13 | partial — provider/env helpers only |
| `lib/documentTypes.ts`, `lib/userSettings.ts`, `lib/upload.ts`, `lib/officeText.ts` | 0 | ✗ |
| `lib/convert.ts`, `lib/spreadsheet.ts`, `lib/docxTrackedChanges.ts` | 0 | ✗ |
| `lib/userDataExport.ts` | 0 | ✗ |
| `lib/courtlistener.ts`, `lib/systemWorkflows.ts` | 0 | ✗ |
| `lib/chat/prompts.ts`, `lib/chat/contextBuilders.ts`, `lib/chat/streaming.ts` | 0 | ✗ |
| `lib/chat/tools/**` (schemas, documentOps, toolDispatcher) | 0 | ✗ |
| `lib/llm/**` (providers, tools, index, rawStreamLog) | ~4 | ✗ (only models.ts) |
| `lib/mcp/**` (client, servers, oauth, types) | 0 | ✗ |
Global: **11.18% statements / 10.98% branches / 14.43% functions / 10.91%
lines**. The global number is low because `src/lib/**` includes several very
large feature libs (toolDispatcher, documentOps, systemWorkflows,
courtlistener, docxTrackedChanges) that dominate the line count.
## TODO — untested libs, in priority order
Each item is meant to be one self-contained PR: add the suite, then raise the
floors in `backend/vitest.config.mts` to just below the new measured numbers.
Size is a rough guess: S ≈ an hour, M ≈ an afternoon.
- [ ] `lib/documentTypes.ts` — pure catalog/lookup of document types; assert
known types resolve and unknown inputs fall back sanely. (S)
- [ ] `lib/chat/prompts.ts` — pure prompt builders; assert key instructions and
interpolated values appear in the output strings. (S)
- [ ] `lib/userSettings.ts` — title/tabular model resolution from which API
keys a user has; reuse the Supabase mock pattern from
`userLookup.test.ts`. (S)
- [ ] `lib/upload.ts` — multer wrapper: assert LIMIT_FILE_SIZE maps to a 413
with the right message and other errors pass through. (S)
- [ ] `lib/officeText.ts` — office XML text extraction; build a tiny in-memory
zip fixture with JSZip and assert extracted/decoded text. (S)
- [ ] `lib/chat/tools/toolSchemas.ts` — assert every tool schema has a name,
description, and well-formed parameters (guards against schema drift). (S)
- [ ] `lib/userApiKeys.ts` (rest) — encrypt/decrypt round-trip and DB
load/store paths with a mocked Supabase client. (M)
- [ ] `lib/storage.ts` (rest) — S3 upload/download/list/delete wrappers with a
mocked AWS SDK client. (M)
- [ ] `lib/userDataExport.ts` — export assembly: given seeded mock tables,
assert the export contains the user's data and nobody else's. (M)
- [ ] `lib/spreadsheet.ts` — parse a small in-memory xlsx fixture; assert sheet
and cell extraction, including empty/edge cells. (M)
- [ ] `lib/chat/contextBuilders.ts` — context assembly from doc stores; assert
doc labels, truncation, and ordering. (M)
- [ ] `lib/docxTrackedChanges.ts` — tracked-changes XML round-trip on a minimal
docx fixture: insert/delete runs, accept/reject. High value: document
integrity. (M)
- [ ] `lib/courtlistener.ts` — API client with mocked fetch: query building,
pagination, and error paths. Legal-research correctness. (M)
- [ ] `lib/systemWorkflows.ts` — mostly data: assert workflow definitions are
well-formed (unique ids, non-empty skill markdown). (S)
- [ ] `lib/llm/tools.ts` + `lib/llm/index.ts` — provider-neutral tool plumbing
and provider selection with mocked provider modules. (M)
- [ ] `lib/mcp/types.ts` + `lib/mcp/servers.ts` — server config validation and
allow-listing logic; security relevant. (M)
- [ ] `lib/mcp/client.ts` + `lib/mcp/oauth.ts` — connection lifecycle and OAuth
token handling with a mocked MCP SDK; security relevant. (M)
- [ ] `lib/llm/rawStreamLog.ts` — log path construction and redaction with a
mocked fs. (S)
- [ ] `lib/chat/tools/documentOps.ts` — start with the pure helpers (diff/match
utilities), not the full tool handlers. (M)
- [ ] `lib/chat/tools/toolDispatcher.ts` — dispatch table routing and argument
validation with stubbed tools; don't try to cover every tool body. (M)
- [ ] `lib/chat/streaming.ts` + `lib/llm/{claude,gemini,openai}.ts` — streaming
loops and provider adapters; hardest to unit test, consider extracting
pure chunk-parsing helpers first. (M)
Not worth unit testing directly: `lib/supabase.ts` and `lib/convert.ts` are
thin wrappers around external services (Supabase auth, LibreOffice); they are
better exercised by the e2e suite.
## Ratchet policy
`backend/vitest.config.mts` enforces global coverage **floors** (currently
statements 11 / branches 10 / functions 14 / lines 10). They are a
no-regression ratchet, not a target:
- **Floors only go up.** Never lower them to get a PR green — that means your
change removed tested behavior or added a large untested lib; add tests
instead.
- **Raise them in the same PR that adds tests.** After your suite passes, run
`npm run test:coverage`, take the new global numbers, and set each floor to
the measured value rounded down to a whole percent.
- Keep the measured numbers in the config comment and the table above honest
when you do.