Problem
tests/integration/invoices/ingest.test.ts contains four it.todo placeholders that have never been implemented. The invoice-ingest endpoint is the production entry point for automated PDF uploads (R2 + Drizzle + period matching + duplicate detection) — leaving its primary tests as todos means we have zero coverage of the auth, validation, happy path, and duplicate handling for one of the riskiest endpoints in the app.
Evidence
tests/integration/invoices/ingest.test.ts:1-9:
import { describe, it } from \"vitest\";
describe(\"POST /api/invoices/ingest\", () => {
// These tests require a running server and DB
it.todo(\"returns 401 with no auth header\");
it.todo(\"returns 400 when no PDF provided\");
it.todo(\"returns 200 with valid PDF and correct Bearer token\");
it.todo(\"returns 409 when submitting same invoice twice\");
});
The endpoint under test is src/app/api/invoices/ingest/route.ts. It uses INVOICE_INGEST_SECRET for Bearer auth, validates content-type and file size, runs extractInvoiceFields, writes a row to invoices and (when matched) billed_costs, and logs to ingestion_log.
Proposed approach
Replace the it.todo calls with real it(...) tests. Use the same integration-test harness already used in tests/integration/sync/*.test.ts (Vitest + real Neon DB).
-
Setup: per-test transaction or per-suite cleanup that truncates invoices, billed_costs, ingestion_log. See existing patterns in tests/integration/sync/.
-
returns 401 with no auth header: POST with no Authorization header → expect 401, no DB writes.
-
returns 401 with bad bearer: (added) POST with Authorization: Bearer wrong → expect 401.
-
returns 400 when no PDF provided: POST with valid bearer but missing or non-PDF body → expect 400 with the expected error JSON shape ({ success: false, error: ... } per project convention).
-
returns 200 with valid PDF and correct Bearer token:
- Use a small fixture PDF in
tests/fixtures/sample-invoice.pdf.
- Stub
getR2Client / extractInvoiceFields (or use a deterministic test extractor).
- POST → expect 200, expect a row in
invoices, expect a change_history row, expect an ingestion_log row with outcome = 'success'.
-
returns 409 when submitting same invoice twice: Submit the same fixture twice → second call returns 409, no second invoices row, ingestion_log records the duplicate outcome.
-
Wire the test file into pnpm test:integration (it should be picked up automatically by the integration glob).
-
Document any fixture or env requirement in tests/integration/README.md (create if missing).
Acceptance criteria
Verification
pnpm test:integration tests/integration/invoices/ingest.test.ts runs green locally with DATABASE_URL pointing at a test branch.
- Manually break the auth check in the route (e.g. always return 200) → confirm the auth tests fail. Revert.
- Break the duplicate detection (e.g. comment out the existence check) → confirm the duplicate test fails. Revert.
Problem
tests/integration/invoices/ingest.test.tscontains fourit.todoplaceholders that have never been implemented. The invoice-ingest endpoint is the production entry point for automated PDF uploads (R2 + Drizzle + period matching + duplicate detection) — leaving its primary tests as todos means we have zero coverage of the auth, validation, happy path, and duplicate handling for one of the riskiest endpoints in the app.Evidence
tests/integration/invoices/ingest.test.ts:1-9:The endpoint under test is
src/app/api/invoices/ingest/route.ts. It usesINVOICE_INGEST_SECRETfor Bearer auth, validates content-type and file size, runsextractInvoiceFields, writes a row toinvoicesand (when matched)billed_costs, and logs toingestion_log.Proposed approach
Replace the
it.todocalls with realit(...)tests. Use the same integration-test harness already used intests/integration/sync/*.test.ts(Vitest + real Neon DB).Setup: per-test transaction or per-suite cleanup that truncates
invoices,billed_costs,ingestion_log. See existing patterns intests/integration/sync/.returns 401 with no auth header: POST with noAuthorizationheader → expect 401, no DB writes.returns 401 with bad bearer: (added) POST withAuthorization: Bearer wrong→ expect 401.returns 400 when no PDF provided: POST with valid bearer but missing or non-PDF body → expect 400 with the expected error JSON shape ({ success: false, error: ... }per project convention).returns 200 with valid PDF and correct Bearer token:tests/fixtures/sample-invoice.pdf.getR2Client/extractInvoiceFields(or use a deterministic test extractor).invoices, expect achange_historyrow, expect aningestion_logrow withoutcome = 'success'.returns 409 when submitting same invoice twice: Submit the same fixture twice → second call returns 409, no secondinvoicesrow,ingestion_logrecords the duplicate outcome.Wire the test file into
pnpm test:integration(it should be picked up automatically by the integration glob).Document any fixture or env requirement in
tests/integration/README.md(create if missing).Acceptance criteria
it.todocalls remain intests/integration/invoices/ingest.test.ts.pnpm test:integrationagainst a Neon test branch.tests/fixtures/with a README.pnpm lint && pnpm typecheckpass.Verification
pnpm test:integration tests/integration/invoices/ingest.test.tsruns green locally withDATABASE_URLpointing at a test branch.