v1.26.0
[1.26.0] — 2026-05-14
Test pyramid (unit → functional → acceptance → e2e) + coverage push to ≥ 93 % line / ≥ 83 % branch. Adopts the 4-tier structure mandated by the v1.25 backlog. Adds 22 new tests targeting the biggest coverage gaps from v1.25's npm run test:coverage report; introduces the tests/acceptance/ directory for cross-endpoint user-journey tests.
📐 Test pyramid documentation
docs(architecture): TESTING.md describes the 4-tier pyramid(docs/architecture/TESTING.md) — single-source explanation of how the suite is structured and where new tests land:- Tier 1 (unit) — pure helpers (
security,parsers,prompts,file-lock,rate-limit,safe-fetch,env-config). No port binding, no FS beyond stubs, no subprocess. - Tier 2 (functional) — per-endpoint contracts.
createApp()against ephemeral port + tempCAREER_OPS_ROOT. - Tier 3 (acceptance) — multi-endpoint user journeys. NEW
tests/acceptance/directory. - Tier 4 (e2e) — Playwright headless Chromium (
tests/playwright-{smoke,full-cycle}.mjs,tests/e2e{,-comprehensive}.mjs).
- Tier 1 (unit) — pure helpers (
- 100% line coverage target is explicitly scoped to working functionality — the
if (isMain) { … }boot block inserver/index.mjsand live-LLM call paths inauto-pipeline.mjsare documented exclusions.
🧪 Tier 2 — Functional gap fills
test(jds): jds-list-create-get.test.mjs— pre-v1.26 only the DELETE path was tested. New file adds 10 tests covering:GET /api/jdsshape on empty + populated statePOST /api/jdswith explicit slug, auto-generated slug, slug normalization warningPOST /api/jdsempty-body / stripped-to-empty-slug 400 responsesGET /api/jds/:namebody roundtrip, 404 on unknown, traversal rejectionserver/lib/routes/jds.mjscoverage: 61.64 % → 100 % line.
test(auto-pipeline): auto-pipeline-rejection-paths.test.mjs— 10 tests covering every URL rejection branch that doesn't need a live LLM:javascript:/file:/// malformed-string / empty / no-key-body- SSRF: loopback, RFC1918, link-local IMDS (169.254.169.254)
mode: 'manual'interaction with rejected URL — error precedes any done eventserver/lib/routes/auto-pipeline.mjsbranch coverage: 50.00 % → 59.38 %.
🧪 Tier 3 — Acceptance (NEW)
-
test(acceptance): jd-evaluate-tracker-flow.test.mjs— first cross-endpoint user journey. Threads 7 endpoints in the order the SPA invokes them:POST /api/jds— save raw JDGET /api/jds— confirm in listGET /api/jds/:name— read body verbatimPOST /api/evaluate(manual fallback) — generate promptPOST /api/tracker— add rowGET /api/tracker— verify presenceGET /api/activity— confirm audit-log entry
Second journey: pipeline-add → preview → tracker → delete cycle.
🧪 Test count
- 480 → 502 unit + acceptance (+22). 32/32 Playwright unchanged.
npm testnow runstests/*.test.mjs tests/acceptance/*.test.mjs.npm run test:coveragesame.npm run test:ciruns all of the above plus the two CI gates from v1.24.1 (check-no-also-leftovers) and v1.25.0 (check-changelog-parity).
Coverage snapshot
all files | 93.66 line | 83.73 branch | 92.91 func
server/lib/security.mjs | 99.30 line
server/lib/safe-fetch.mjs | 95.81 line
server/lib/file-lock.mjs | 93.15 line
server/lib/rate-limit.mjs | 100.00 line
server/lib/parsers.mjs | 99.57 line
server/lib/routes/jds.mjs | 100.00 line ← was 61.64 in v1.25
server/lib/routes/tracker.mjs | 100.00 line
server/lib/routes/reports.mjs | 100.00 line
server/lib/routes/activity.mjs| 100.00 line
Remaining < 95 % line modules are gated by live-LLM / spawn-mock complexity:
auto-pipeline.mjs(46 %) — uncovered region is the live Anthropic / Gemini evaluate path + report-save + tracker-write SSE flow. Out of scope for the 100 % target per TESTING.md "Goal: 100% line coverage of working functionality".batch.mjs(67 %) — uncovered region isstreamNodeScriptspawn ofbatch-runner.sh. Out of scope (subprocess mocking gap).cv-import.mjs(77 %) — uncovered region is pandoc / pdftotext fallback paths when the system tools are missing. Out of scope (env-dependent).
Verification
$ npm run test:ci
# 502 / 502
# ✓ no .also( leftovers in views/
# ✓ CHANGELOG parity: all 8 locales at v1.26.0
$ npm run test:coverage 2>&1 | grep '^# all files'
# all files | 93.66 | 83.73 | 92.91
$ ls tests/acceptance/
# jd-evaluate-tracker-flow.test.mjsBreaking changes
None.
Out of scope (v1.27+)
| Item | Notes |
|---|---|
Live LLM-path coverage in auto-pipeline.mjs |
Needs SDK-adapter mock + withFileLock stub + report-save stub. Currently 46 % line; would push toward 95 % with the mock harness. |
Subprocess-mocked coverage for batch.mjs::streamNodeScript |
Needs spawn-mock; would push 67 % → 90 %. |
cv-import.mjs pandoc / pdftotext fallback path |
Needs env-injected which() stub. |
| G-005 (A-F report block realignment) | Still waiting on coordinated parent commit. |