Estado de Tests y Plan de Hardening
Test State & Hardening Plan
Sección titulada «Test State & Hardening Plan»Scope: DEVELOPMENT / localhost only. No production, no CI cloud, no deploy. The goal is a trustworthy, reproducible local test battery and a strong hardening roadmap up to (but not beyond) the dev boundary.
Status: iterative — this document is built and revised across sessions. Iteration 0 below is the verified baseline as of 2026-05-31.
Method: the verdicts below were produced by destroying the docker volumes and rebooting the stack cold from fixtures, then running the real suites — not by trusting cached state.
Iteration 0 — Verified baseline (2026-05-31, branch coveris-b-integration)
Sección titulada «Iteration 0 — Verified baseline (2026-05-31, branch coveris-b-integration)»Executive summary
Sección titulada «Executive summary»| Layer | Verdict | One-line |
|---|---|---|
| Backend (Django/DRF/pytest) | 🟢 HEALTHY | Cold boot clean from fixtures; 713 passed, 1 xfail, 0 failures in 2m13s. |
| Backend integration / contract | 🟢 HEALTHY | -m api 286 passed, -m regression 60 passed; API.md↔test coverage guard in place. |
| Frontend build (Angular 21) | 🔴 BROKEN | bun run build fails — 2 TS errors in roster-detail.component.ts. |
| Frontend unit (Vitest) | 🔴 BLOCKED | 0 specs run — Angular compile halts before any spec executes. ~70 spec files, ~721 cases, all currently un-runnable. |
| Frontend static | 🟢 PASS | bun run test:static — 1 file, 3 tests pass. |
| E2E (any layer) | ⚪ NONE | No Playwright/e2e exists; deferred post-MVP per ADR-009-d. |
The single blocking issue is the frontend build. Until it compiles, the entire 700+ case frontend suite is dark — we have no signal on the frontend, and the green backend number can give a false sense of overall health.
Backend — detail
Sección titulada «Backend — detail»- Cold boot:
docker compose down -v→build→up -dreachedhealthy(~70s). Health verified inside the container via/api/health/. - Seed: fixtures auto-load in
backend/entrypoint.sh(loaddata mock_clinic.yaml+mock_employees.yaml, migrated from 11 seed commands in commite3bd1a2). Seeded 6 users, 31 employees. Idempotent (get_or_createsuperuser,loaddataoverwrite). - Suite: 42 test files / 714 functions. pytest + pytest-django, config in
backend/pyproject.toml(markers:slow,api,regression). Run in-container:docker compose exec -T api pytest -q. - Known/accepted gaps:
- 1
xfail:test_login_throttle(DRF caches throttle scope at import; local sets rateNone). Accepted per ADR-009-b. KNOWN_UNTESTEDallowlist: 57 endpoints documented in API.md but without contract tests — mostly CRUD detail/update/delete and the 12 Employee + 3 Assignment FSM transition endpoints. Guarded bytests/test_contract_coverage.py(fails if API.md drifts).- No Cognito auth tests (SimpleJWT only in dev — fine for localhost scope).
- No coverage % enforced (pytest-cov available, not wired).
UnorderedObjectListWarningonPositionquerysets (cosmetic; missing default ordering).
- 1
Frontend — detail
Sección titulada «Frontend — detail»- Framework: Vitest 4 via Angular
@angular/build:unit-test. Coverage threshold configured at 80% (vitest.config.ts) but never reached because the suite can’t run. - Blocking build errors — both in
frontend/src/app/features/roster/roster-detail.component.ts:- L342
TS2339: Property 'tagGridColumns' does not exist on type 'RosterDetail'— declared at L806 but not template-visible (likelyprivate; templates needpublic/protected), or a stale reference. - L344
TS2345: 'TagGridTag' is not assignable to 'ApiEmployeeTag'—kdx-tag-grid’s(remove)output emits the display-onlyTagGridTag, butremoveTag()(L1040) still expects the fullApiEmployeeTag. Types not kept in sync during thekdx-tagconsolidation.
- L342
- Root cause context: in-flight refactor on this branch —
cv-tag+emp-tagcomponents deleted and consolidated intokdx-tag/kdx-tag-grid;no-mock-imports.spec.tsrewritten to build-time glob scanning. The consolidation leftroster-detailhalf-migrated. - 1 skipped test:
login-card.component.spec.ts:52it.skip(...)(error-message display) — undocumented skip.
Hardening roadmap
Sección titulada «Hardening roadmap»Ordered by leverage. Each item is dev-local only. P0 = unblock signal; P1 = trust the signal; P2 = widen coverage; P3 = make it reproducible/enforced.
P0 — Unblock the frontend (nothing else is trustworthy until this is green)
Sección titulada «P0 — Unblock the frontend (nothing else is trustworthy until this is green)»- Fix the two
roster-detail.component.tstype errors (maketagGridColumnsprotected/public; reconcileTagGridTagvsApiEmployeeTaginremoveTag— adapt the handler or the emitted type). - Re-run
bun run build→ must succeed. - Re-run
bun run test(non-watch) → establish the real frontend pass/fail baseline. Record it here as Iteration 1. - Triage every spec broken by the
kdx-tagconsolidation; update or delete stale specs for the removedcv-tag/emp-tag.
P1 — Trust the signal
Sección titulada «P1 — Trust the signal»- Resolve or formally document the
login-cardit.skip(fix or write the rationale inline). - Add default ordering to
Positionquerysets to killUnorderedObjectListWarning(pagination determinism). - Make the unit runner non-watch by default for scripted runs (a
test:ci-style script using the run-once flag) so agents/Make never hang. - Verify
make test(backend + frontend) runs end-to-end green after P0.
P2 — Widen coverage (close the documented gaps)
Sección titulada «P2 — Widen coverage (close the documented gaps)»- Backend: write contract tests for the highest-risk slice of the 57
KNOWN_UNTESTEDendpoints — prioritize the 15 FSM transition endpoints (Employee ×12, Assignment ×3), then CRUD delete/update. Remove each fromKNOWN_UNTESTEDas it lands. - Frontend: add specs for the Hours (
features/hours/) feature — currently zero coverage. - Wire
pytest-covand set a starting backend coverage floor (report-only first, then enforce). - Enforce the existing 80% Vitest threshold once the suite runs (currently inert).
P3 — Reproducibility & enforcement (dev boundary)
Sección titulada «P3 — Reproducibility & enforcement (dev boundary)»- A single
make test-coldtarget:down -v→ build → up → wait-for-health (in-container) → seed check → backend pytest → frontend test+build. One command proves the whole local battery from scratch. - A pre-push / local git hook (or documented one-liner) that runs
bun run build+ both suites — catch baseline breakage like P0 before it’s committed. - Document the canonical commands in one place (README/Makefile):
bun run test(NOTbun test/bunx vitest), in-containerpytest, health-check-inside-container. - (Stretch, still dev-local) Stand up the deferred Playwright e2e skeleton (ADR-009-d) against the docker stack — smoke path: login → dashboard → roster.
Canonical commands (reference)
Sección titulada «Canonical commands (reference)»# Backend — cold, from repo root (authoritative health = inside container)docker compose down -v && docker compose build && docker compose up -ddocker compose exec -T api python -c "import urllib.request; print(urllib.request.urlopen('http://localhost:8000/api/health/',timeout=5).read().decode())"docker compose exec -T api pytest -q # full suitedocker compose exec -T api pytest -m api -q # contractdocker compose exec -T api pytest -m regression -q # regression
# Frontend — from frontend/bun run test # unit (ng test → Vitest); ensure non-watch for scripted runsbun run test:static # static checksbun run build # MUST pass — currently the blocker
# Wrappersmake test-backend | make test-frontend | make test | make clean (down -v)Changelog
Sección titulada «Changelog»- 2026-05-31 — Iteration 0: Baseline captured via cold docker rebuild. Backend green (713/1xfail/0fail). Frontend build broken (
roster-detail.component.ts×2 TS errors) → unit suite fully blocked. Roadmap drafted.