test(api): Worker export/CSV — fill gaps + lifecycle test

Drove src/lib/csv.ts to 100% stmts/branch/funcs/lines (was 97.95%/55.55%):
- added a null-fallback row test covering every ?? default (activityName,
  userName, insoleType→Kurk, pairCount→2, duration/paused→0) and the null
  end-time branch (line 65).
- added CSV-escaping edge tests: commas, embedded quotes, and newlines inside
  a field stay inside the quoted cell.
- added formatDuration edge (hours >99 → 100:00:00).
- added a /api/export ordering-by-start-time behavior test and adopted
  resetDb per-test isolation in the export suite.

No bugs found; CSV code behaves correctly. sessions.ts /api/export route
already at 100%. Full api suite green (150 tests).
This commit is contained in:
Bas van Rossem
2026-07-22 12:24:04 +02:00
parent 9ecbf952d3
commit b72076ee15
3 changed files with 105 additions and 3 deletions

View File

@@ -127,3 +127,29 @@ Guaranteed behaviors:
- Lifecycle: start → pause → (backdate) resume accumulates paused time → (backdate) stop excludes
paused time from worked duration → the completed session appears in history with its activity
name → `GET /api/export` returns a CSV with exactly the header + one data row.
## Worker export/CSV
Src covered: `src/lib/csv.ts` — 100% stmts/branch/funcs/lines; the `/api/export` route in
`src/routes/sessions.ts` — 100%. No `c8 ignore`s needed (every fallback branch is exercised).
Guaranteed behaviors:
- `buildSessionsCsv(rows)` (worker self-export, `includeWorker` defaults to false) emits the exact
legacy header `ID,Task,Insole Type,No. of Insoles,Date,Total Duration,Paused Duration,Start
Time,End Time` (each cell quoted) with no Worker column.
- `buildSessionsCsv(rows, { includeWorker: true })` prepends a `Worker` column carrying `userName`.
- Every field is quoted; `quote` escapes embedded double quotes (doubled) and keeps commas and
newlines inside the quoted cell — a comma/quote/newline in an activity name never breaks the
column or row structure.
- Legacy fallbacks: a null `activityName`/`userName` renders `''`, null `insoleType` renders
`Kurk`, null `pairCount` renders `2`, null `durationSeconds`/`pausedSeconds` render `00:00:00`,
and a null `endTime` renders an empty End Time cell.
- `formatDuration` renders zero-padded `HH:MM:SS`, handles zero (`00:00:00`), and lets hours exceed
99 (`360000 → 100:00:00`).
- `GET /api/export`: 401 without a token; includes only the caller's `completed` sessions
(active/discarded and other users' rows excluded); rows ordered by start time ascending; sets the
`text/csv` content-type and the `attachment; filename="insole-production-report.csv"` disposition
header.
- Lifecycle: covered by the worker-session anchor (`test/integration/worker-session-lifecycle.test.ts`),
whose final step asserts `GET /api/export` returns the header + exactly one completed-session row.