# Testing

> Audience: vendor engineers and the operator before handover.
> Goal: explain what is tested today, where the gaps are, and how to add coverage safely.
> Priority: **High** — tests are the primary safety net for the Azure port.

---

## 1. Tooling

- **Runner:** [Vitest](https://vitest.dev/) (`npm run test`).
- **Coverage:** v8 (`npm run test:coverage`).
- **Config:** [`vitest.config.ts`](vitest.config.ts).
- **Environment:** `node` (no JSDOM). Tests are Node-native; no browser setup.
- **Discovery:** files matching `__tests__/**/*.test.ts` only. Co-located tests inside `app/` or `components/` are not picked up by default.
- **Aliases:** `@` → repo root (mirrors `tsconfig.json`).

```bash
npm run test           # single run
npm run test:watch     # watch mode
npm run test:coverage  # v8 coverage report
```

The coverage `include` list is intentionally narrow:

```
lib/entitlement/**
lib/provisioning/**
lib/owner-audit/**
lib/tenant/**
lib/demo/**
```

Coverage on UI, API route handlers, and most of `lib/` is **not** tracked by the v8 reporter today.

---

## 2. Current test surface

Total: **60 test files** (count via `find . \( -name "*.test.ts" -o -name "*.test.tsx" \) -not -path "*/node_modules/*" | wc -l` as of 2026-05-26, after Batch 6 test foundation).

Test files are distributed across three locations:

### `__tests__/` (root-level, 14 files)

| Test file                                          | Domain                              | What it covers (high level)                                                                                                          |
| -------------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `__tests__/cache-adapter.test.ts`                  | Tenant cache                        | Adapter contract.                                                                                                                    |
| `__tests__/csp-report.test.ts`                     | API route                           | `/api/csp-report` parsing + structured logging.                                                                                      |
| `__tests__/intake-availability.test.ts`            | Intake module                       | Consultant availability logic.                                                                                                       |
| `__tests__/intake-board-transitions.test.ts`       | Intake module                       | Kanban board state transitions.                                                                                                      |
| `__tests__/intake-field-builder.test.ts`           | Intake module                       | Dynamic field-definition builder.                                                                                                    |
| `__tests__/intake-phase-config.test.ts`            | Intake module                       | Phase configuration rules.                                                                                                           |
| `__tests__/intake-promote.test.ts`                 | Intake module                       | Intake-to-project promotion logic.                                                                                                   |
| `__tests__/oee-analysis.test.ts`                   | OEE module                          | OEE loss analysis aggregations.                                                                                                      |
| `__tests__/oee-measurement-engine.test.ts`         | OEE module                          | OEE KPI calculation (Availability × Performance × Quality).                                                                         |
| `__tests__/project-edit-form-helpers.test.ts`      | Project form helpers                | Pure helpers used by the project edit form.                                                                                          |
| `__tests__/project-edit-form-payload.test.ts`      | Project form payload                | Form → API payload shape.                                                                                                            |
| `__tests__/seeder.test.ts`                         | Demo seeder                         | Demo-pack seed/reset behaviour.                                                                                                      |
| `__tests__/vsm-editor-logic.test.ts`               | Value-stream-map editor             | Editor business logic (no DOM).                                                                                                      |
| `__tests__/security/rls-user-scoped.test.ts`       | Security / RLS                      | 40 `it.todo()` stubs for user-scoped RLS isolation — requires Docker-Postgres + 2 users (see `docs/E2E.md`). Skipped in CI. |

### `lib/` sub-directories (36 files across modules)

| Test file                                                     | Domain                 | What it covers                                            |
| ------------------------------------------------------------- | ---------------------- | --------------------------------------------------------- |
| `lib/__tests__/env-schema.test.ts`                            | Config                 | Zod env-var schema validation.                            |
| `lib/__tests__/env.test.ts`                                   | Config                 | `lib/env.ts` compat layer.                                |
| `lib/__tests__/logger.test.ts`                                | Observability          | Structured logger + redaction.                            |
| `lib/__tests__/qaf-parser.test.ts`                            | QAF                    | QAF document parser.                                      |
| `lib/agenda/__tests__/colors.test.ts`                         | Agenda                 | Color-palette helpers.                                    |
| `lib/agenda/__tests__/export-excel.test.ts`                   | Agenda export          | Excel export shape + data integrity.                      |
| `lib/agenda/__tests__/export-model.test.ts`                   | Agenda export          | Export model transformations.                             |
| `lib/agenda/__tests__/export-pdf.test.ts`                     | Agenda export          | PDF export (jsPDF output).                                |
| `lib/agenda/__tests__/i18n.test.ts`                           | Agenda                 | i18n string lookups.                                      |
| `lib/agenda/__tests__/templates.test.ts`                      | Agenda                 | Template rendering logic.                                 |
| `lib/agenda/__tests__/time-engine.test.ts`                    | Agenda                 | Time-slot scheduling engine.                              |
| `lib/audit/__tests__/file-events.test.ts`                     | Audit                  | File-event audit log entries.                             |
| `lib/gdpr/__tests__/deletion.test.ts`                         | GDPR                   | User data deletion flow.                                  |
| `lib/gdpr/__tests__/export.test.ts`                           | GDPR                   | User data export format.                                  |
| `lib/lsc-workshop/__tests__/cycle-histogram.test.ts`          | LSC                    | Cycle-time histogram bins.                                |
| `lib/lsc-workshop/__tests__/measures-matrix.test.ts`          | LSC                    | Measures matrix aggregation.                              |
| `lib/lsc-workshop/__tests__/observations.test.ts`             | LSC                    | Observation data helpers.                                 |
| `lib/lsc-workshop/__tests__/oee-trend.test.ts`                | LSC / OEE              | OEE trend calculation.                                    |
| `lib/lsc-workshop/__tests__/pareto.test.ts`                   | LSC                    | Pareto chart data shaping.                                |
| `lib/lsc-workshop/__tests__/time-composition.test.ts`         | LSC                    | Time composition breakdown.                               |
| `lib/observability/__tests__/spans.test.ts`                   | Observability          | OTel span helper contracts.                               |
| `lib/pmo/__tests__/members.test.ts`                           | PMO                    | Team-member logic.                                        |
| `lib/pmo/__tests__/weekly.test.ts`                            | PMO                    | Weekly target helpers.                                    |
| `lib/pmo/__tests__/workstreams.test.ts`                       | PMO                    | Workstream data model.                                    |
| `lib/project/__tests__/project-tabs-config.test.ts`           | Project                | Tab-visibility config by Auftragstyp.                     |
| `lib/qaf/__tests__/column-groups.test.ts`                     | QAF                    | Column grouping logic.                                    |
| `lib/qaf/__tests__/comparison.test.ts`                        | QAF                    | QAF document comparison.                                  |
| `lib/qaf/__tests__/process-mapping.test.ts`                   | QAF                    | Process mapping helpers.                                  |
| `lib/reporting/__tests__/aggregations.test.ts`                | Reporting              | KPI aggregation correctness.                              |
| `lib/security/__tests__/rate-limit.test.ts`                   | Security               | Rate-limit adapter contract.                              |
| `lib/security/__tests__/sanitize.test.ts`                     | Security               | Input sanitization helpers.                               |
| `lib/security/__tests__/secure-response.test.ts`              | Security               | Response-header helpers.                                  |
| `lib/stopwatch/__tests__/pending-measurements.test.ts`        | Stopwatch              | Pending measurement queue logic.                          |
| `lib/customers/bmw/branding/__tests__/bmw-group-logo.test.tsx`       | Branding        | Logo component rendering.                                 |
| `lib/customers/bmw/branding/__tests__/bmw-group-logo-auto.test.tsx`  | Branding        | Auto-mode logo variant.                                   |
| `lib/auth/__tests__/safe-redirect.test.ts`                    | Auth / Security | 16 assertions on `safeRedirectPath` — SEC-004 open-redirect guard (Batch 6). |

### `app/api/` (3 new files — Batch 6)

| Test file                                                              | Domain            | What it covers                                                                                 |
| ---------------------------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------- |
| `app/api/v1/oee/__tests__/route.test.ts`                               | OEE v1 API        | 11 assertions: GET filter uses `calendar_week` not `week_number`; POST maps `week_number`→`calendar_week` on insert; missing fields → 400; unauthenticated → 401 (F-007). |
| `app/api/admin/__tests__/permission-gates.test.ts`                     | Admin routes      | 9 assertions: 401 when no session; 403 when role=consultant; auth-gate passed when role=admin — covers `/admin/users`, `/admin/audit`, `/admin/users/lock` (GAP-03). |
| `app/api/admin/__tests__/blocked-account-gate.test.ts`                 | Auth / SEC-018    | 4 assertions: locked/inactive/deleted/deactivated account_status → getUserSession returns null → route returns 401. |

### `components/` (7 files)

| Test file                                               | Domain        | What it covers                        |
| ------------------------------------------------------- | ------------- | ------------------------------------- |
| `components/brand/__tests__/action-bar.test.tsx`        | UI / Branding | ActionBar component.                  |
| `components/brand/__tests__/empty-state.test.tsx`       | UI / Branding | EmptyState component.                 |
| `components/brand/__tests__/filter-chip.test.tsx`       | UI / Branding | FilterChip component.                 |
| `components/brand/__tests__/info-banner.test.tsx`       | UI / Branding | InfoBanner component.                 |
| `components/brand/__tests__/kpi-card.test.tsx`          | UI / Branding | KpiCard component.                    |
| `components/layout/__tests__/env-badge.test.tsx`        | UI / Layout   | EnvBadge component.                   |
| `components/ui/__tests__/badge.test.tsx`                | UI            | Badge component.                      |

---

## 3. Known test gaps

These gaps are explicitly known and documented. The vendor will likely need to close them before the Azure cut-over hardening phase.

| Area                                                  | Gap                                                                                                                              | Priority    |
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **RLS enforcement (live DB)**                         | No automated query-level tests against a real Postgres instance with RLS active. `__tests__/security/rls-user-scoped.test.ts` contains 40 `it.todo()` stubs — requires Docker-Postgres + 2 provisioned users (see `docs/E2E.md`). (Note: cross-tenant tests became user-scoped in Batch 2 — control plane removed.) | **Critical** |
| **E2E / browser flows**                               | Playwright scaffold added (`e2e/golden-path.spec.ts`, 5 flows GP-01..GP-05 as `test.fixme`). Requires running app + seeded DB. See `docs/E2E.md`. `@playwright/test` not yet installed. | High        |
| **API route handlers (`app/api/**/route.ts`)**        | Permission gates for admin routes now covered (Batch 6: 3 representative routes, 401/403/pass-through). 50+ routes still lack input-validation and success-path tests. | High        |
| **Stopwatch offline data loss**                       | `stopwatch-client.tsx` writes directly to Supabase, bypassing the offline queue. No test verifies the data path under simulated network failure. See `docs/TECHNICAL_DEBT.md`. | High        |
| **Planning offline sync**                             | `planning-client.tsx` does not call the offline queue for assignments despite `registry.ts` having the entry. Silent data loss on network outage. No test. | High        |
| **OpenAPI ↔ implementation drift**                    | `npm run check:openapi` enforces presence; no contract test verifies response shape matches the spec.                            | High        |
| **Service-role usage**                                | Privileged paths (`@/lib/supabase/admin` importers) are not covered by allow-list assertions.                                    | High        |
| **Storage interactions**                              | Bucket access is not covered.                                                                                                    | Medium      |
| **Email queue / notifications**                       | `lib/email/notifications` is not test-covered.                                                                                   | Medium      |
| **Export integrity**                                  | `lib/export/export-service.ts` (core export, PPTX + PDF) has zero test coverage. Agenda-specific export is covered.             | Medium      |
| **Reporting consistency**                             | Management dashboard aggregates KPIs independently of the OEE engine; no test verifies consistency between them.                 | Medium      |
| **UI permission gates**                               | Role-based button/tab visibility is not covered by component tests.                                                              | Medium      |
| **Background and scheduled work**                     | None present today; would need coverage if/when added.                                                                           | Low         |

---

## 4. Recommended smoke checks (manual)

When confidence is needed in lieu of full E2E, run these by hand:

1. `npm run dev` and load `http://localhost:3000/api/v1/health` — expect a 200 JSON body.
2. Login as a tenant user; visit `/dashboard` and verify the visit list loads.
3. Create a visit, add one process step, take one cycle measurement, save.
4. Visit `/management` analytics and verify charts render without errors in the browser console.
5. Open the owner portal as the owner role and load `/owner/tenants` — verify tenants are listed.

If any of these fails the install is broken, regardless of what `npm test` reports.

---

## 5. Adding tests

- Place new tests under a `__tests__/` directory co-located with the code (e.g. `lib/auth/__tests__/`, `app/api/admin/__tests__/`) or under the root `__tests__/`. Both patterns are covered by the `**/__tests__/**/*.test.ts` glob in `vitest.config.ts`.
- Prefer **pure helpers** for new logic — they are easy to test and have no Supabase dependency.
- For Supabase-touching code, follow the pattern in `provisioning.test.ts`: build a thin fake client in the test, never call out to a real Supabase.
- API route handlers can be invoked directly by importing the route file and calling its exported `GET` / `POST`. Build a `Request` with `new Request(url, init)`.
- New domains worth covering should be added to `vitest.config.ts` `coverage.include` so they show up in the v8 report.

---

## 6. Interpreting failures

| Symptom                                          | Likely cause                                                                                          |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
| `Cannot find module '@/...'`                     | `vitest.config.ts` aliases out of sync with `tsconfig.json`.                                          |
| `Missing SUPABASE_SERVICE_ROLE_KEY`              | A test triggered the privileged-env loader. Tests must mock, never real-call.                          |
| `getClaims is not a function`                    | Wrong `@supabase/ssr` version cached — `rm -rf node_modules && npm install`.                          |
| Snapshot mismatch                                | Behaviour change. Update only if the new behaviour is intended; otherwise revert.                       |
| Flaky assignment / planning test                 | Date-of-week computation. Tests should freeze time with Vitest's fake timers — file an issue if not.    |
| `check:openapi` failure but no schema diff       | OpenAPI document JSON has a trailing whitespace / non-deterministic sort. Re-run; if persistent, file. |

If a test fails on `main` immediately after install, this is a real failure — the suite is run on every PR and is expected to be green.

---

## 7. Out of scope for this branch

The following intentionally were **not** added in the foundation-readiness branch:

- New unit tests.
- New E2E tests (Playwright / Cypress).
- Real-PG RLS suite.
- Mutation testing / property tests.

These are explicit handover-time decisions for the vendor. See `docs/foundation/vendor-handover-checklist.md`.
