testing coverage - smart-village-solutions/sva-studio GitHub Wiki
Dieses Dokument beschreibt den standardisierten Coverage-Workflow im Nx Monorepo:
- einheitliche Testtargets (
test:unit,test:coverage,test:integration) - Coverage-Gates pro Paket und global
- Mindest-Floors und Hotspot-Floors für kritische Module
- PR-Transparenz via CI Summary + Artefakte
- stufenweiser Rollout mit Baseline und Ratcheting
Jedes Projekt soll folgende Targets bereitstellen:
-
lint: ausführbarer Qualitäts-Check (kein Platzhalter) -
typecheck: TypeScript-Strict-Check für den produktiven Projekt-Scope -
test:unit: schnelle, stabile Unit-Tests -
test:coverage: Unit-Tests mit Coverage-Reporting -
test:integration: infra-abhängige Tests (z. B. Redis, echte Services)
pnpm test:types
pnpm test:unit
pnpm test:coverage
pnpm test:integrationpnpm test:types ist bindend und umfasst neben den Core-/Library-Builds auch den dedizierten Nx-Typecheck der React-App (sva-studio-react:typecheck). Debug-Routen unter src/routes/__debug/ sind dabei bewusst ausgeschlossen, damit optionale Diagnose-Abhängigkeiten den regulären App-Typecheck nicht verfälschen.
pnpm test:coverage:affectedpnpm test:coverage:prDas Kommando führt dieselben betroffenen Coverage-Targets wie der PR-Workflow aus und prüft danach die Patch-Coverage lokal gegen den Zielwert von 80%.
pnpm test:prDas Kommando bildet den blockierenden GitHub-PR-Workflow für lokale Vorprüfung nach:
check:file-placementnx affected --target=test:coverage --base=origin/main-
patch-coverage-gate --base=origin/mainfür geänderte, ausführbare Zeilen im PR-Diff -
coverage-gateim PR-Modus mit optionalen Summary-Dateien complexity-gatetest:integration- React-App-Build für denselben Build-Pfad wie im Coverage-Workflow
Nicht Bestandteil von pnpm test:pr sind externe Plattform-Auswertungen wie SonarCloud, Codecov oder CodeQL. Die lokale New-Code-/Patch-Coverage wird aber jetzt bereits vor dem Push geprüft, sodass die häufigste Abweichung zwischen lokalem PR-Gate und Sonar früher sichtbar wird.
Der GitHub-Workflow erzeugt vor dem SonarCloud-Scan mit pnpm sonar:prepare-lcov einen zusammengefassten
Report unter artifacts/sonar/lcov.info. Das Skript schreibt alle SF:-Einträge repo-relativ um, weil
Vitest in Workspace-Packages projektlokale Pfade wie src/index.ts ausgibt. Ohne diese Normalisierung
kann SonarCloud LCOV-Pfade aus mehreren Packages nicht zuverlässig dem Quellcode am Repository-Root
zuordnen.
Die CPD-Ausnahmen in sonar-project.properties sind auf generierte Artefakte, Übersetzungsressourcen und
dokumentierte Migrationsspiegel beschränkt. Aktuell betrifft das die Data-Repository-Extraktion
(packages/data-repositories/src/**) und die verbleibenden App-Spiegel der Studio-UI-Extraktion.
Neue fachliche Duplikate sollen weiterhin refaktoriert werden.
Nur nach bewusstem Team-Entscheid:
pnpm coverage-gate --update-baselinePolicy-Dateien:
tooling/testing/coverage-policy.jsontooling/testing/coverage-baseline.json
Regeln:
- Gates werden pro Projekt und global ausgewertet
- Floors werden an der zuletzt stabil gemessenen Coverage ausgerichtet und danach per Ratcheting nachgezogen
- Abfälle gegen Baseline über der erlaubten Schwelle schlagen fehl
- Exempt-Projekte sind in der Policy explizit dokumentiert
- Kritische Projekte können strengere
minimumFloorserhalten als normale Projekt-Floors - Kritische Hotspots können über
hotspotFloorsauf Datei-Ebene auslcov.infoabgesichert werden - Dateien dürfen nur in gut begründbaren Ausnahmefällen aus Coverage- oder New-Code-Gates ausgenommen werden.
- Zulässige Ausnahmefälle sind insbesondere generierte Artefakte oder ressourcenartige Dateien, bei denen Coverage- oder CPD-Metriken systematisch kein sinnvolles Qualitätssignal liefern.
- „schwer testbar“, „zu groß“ oder „orchestriert nur andere Funktionen“ sind für sich allein keine ausreichenden Gründe für eine Exclusion; in diesen Fällen sind stattdessen Tests zu ergänzen oder die Datei gezielt zu refactoren.
Kritische Coverage-Regeln liegen in criticalProjects der Policy.
Beispiele:
- IAM-Zielpackages: projektweite Mindest-Floors liegen direkt auf
auth-runtime,iam-admin,iam-governanceundinstance-registry; historischeauth-Hotspots sind entfernt. -
routing: Hotspot-Floor fürauth.routes.server.ts -
core: Security- und IAM-Hotspots fürfield-encryption.tsundauthorization-engine.ts -
sdk: Hotspots fürrequest-context.server.tsundmonitoring-client.bridge.server.ts -
sva-studio-react: Hotspots füriam-user-events.tsund-iam.models.ts
Hinweis: In tooling/testing/coverage-policy.json werden Hotspots immer auf TypeScript-Quelldateien definiert. Das Coverage-Gate mappt lcov-SF:-Einträge bei Bedarf auf diese Quellpfade zurück.
Empfohlener Testzuschnitt für große Handlerdateien:
- Request-Parsing, Filterlogik, Mapper und Konfliktentscheidungen als reine Helfer absichern
- Handler-Orchestrierung mit wenigen gezielten Server-Tests auf Rollen, CSRF, Idempotency und Seiteneffekte prüfen
- Große Mock-Setups nur für die eigentliche Integrationskante einsetzen, nicht für jede einzelne Branch
- Kleine verhaltensneutrale Extraktionen oder package-interne Helper-Exports sind zulässig, wenn sie die Absicherung vereinfachen
Wenn die Komplexität eines kritischen Hotspots steigt, darf der bestehende Floor nicht abgesenkt werden. Stattdessen muss die Absicherung gleich bleiben oder feiner/höher nachgezogen werden.
Workflow: .github/workflows/test-coverage.yml
- Pull Requests:
- Job
Coverage Gate:nx affected --target=test:coveragegegen den PR-Base-Branch - Job
Complexity Gate: separates, blockierendes Komplexitäts-Gate - Job
PR Integration Gate:nx affected --target=test:integration, exklusivemonitoring-client - Reine Doku-/Meta-PRs starten die Workflows weiterhin, beenden die betroffenen Jobs aber bewusst früh als erfolgreicher No-op, damit Required Checks nicht im Status
expectedhängen bleiben
- Job
- Main + Nightly:
- Job
Coverage Gate:test:coverage(voll) - Job
Complexity Gate: blockierend - Job
Integration Gate: voller, verpflichtender Integrationslauf
- Job
| Workflow / Jobname in GitHub | Zweck | Trigger-Modell |
|---|---|---|
Coverage Gate |
Coverage für affected/full + internes Coverage-Gate | alle PRs, main, nightly |
Complexity Gate |
Repository-weites Komplexitäts-Gate | alle PRs, main, nightly |
PR Integration Gate |
affected test:integration außer Monitoring-Stack |
Pull Requests |
Integration Gate |
voller Integrationslauf |
main, nightly |
App E2E Smoke |
Browser-Smoke für App-Routen | pfadbasiert |
monitoring-stack |
Monitoring-spezifische Docker-/Stack-Checks | pfadbasiert |
Schema Diff Gate |
Schema-Diff gegen Staging | pfadbasiert |
check-file-placement |
Dateiplatzierungs-Regeln | alle PRs und main
|
Empfehlung für main:
- immer required:
Lint / lintUnit / unitTypes / typesCoverage GateComplexity Gate-
PR Integration Gatefür Pull Requests -
Integration Gatefürmain check-file-placement
- pfadabhängig required:
App E2E Smokemonitoring-stackSchema Diff Gate
Die wichtigsten Workflows schreiben eine kurze GITHUB_STEP_SUMMARY mit Scope, Ergebnis und Artefaktname. Ziel ist, dass Reviews die relevanten Nachweise direkt im PR-UI finden, ohne zuerst in die kompletten Logs zu wechseln.
Für Team- und CI-weite Wiederverwendung von Nx-Artefakten ist Nx Cloud der vorgesehene Standard. Laut offizieller Nx-Dokumentation wird ein bestehendes Workspace-Repo per nx connect angebunden; dabei wird ein nxCloudId in nx.json hinterlegt und im Repository committed. Für produktive Setups empfiehlt Nx außerdem eine Ende-zu-Ende-Verschlüsselung über NX_CLOUD_ENCRYPTION_KEY.
Empfohlene Reihenfolge:
- Workspace mit Nx Cloud verbinden:
pnpm nx connect
- Den erzeugten
nxCloudId-Patch nachnx.jsonuebernehmen. - In GitHub Actions ein Secret
NX_CLOUD_ENCRYPTION_KEYanlegen. - Das Secret in den relevanten Workflows als Environment-Variable durchreichen.
- Fuer echte Deploy-Artefakte den Cache bewusst umgehen, wenn ein Lauf ein produktiv ausgerolltes Artefakt erzeugt.
Wichtig:
- Keine DIY-Bucket- oder Shared-FS-Remote-Caches fuer PR-Schreibzugriffe einfuehren. Nx weist aktuell explizit auf Cache-Poisoning-Risiken bei self-hosted Bucket-Loesungen hin.
- Solange kein
nxCloudIdvorliegt, bleibt das Repository absichtlich bei lokalem Cache plusaffected. - Die Aktivierung ist ein kleiner, separater Follow-up, weil dafuer ein echter Nx-Cloud-Workspace benoetigt wird.
Codecov bewertet im Pull-Request zwei getrennte Sichten:
-
project: Gesamt-Coverage des gemessenen Codebestands mit Zielwert75% -
patch: Coverage des neu geänderten Codes mit Zielwert80%
Beide Codecov-Statuschecks sind im Projekt informational. Bindend bleibt die interne Governance:
- für Pull Requests
pnpm test:coverage:pr - für die allgemeine Coverage-Governance
pnpm coverage-gate
Wichtig:
- Codecov berücksichtigt nur Projekte, für die im PR-Lauf auch tatsächlich
lcov.infohochgeladen wird. - Projekte aus
exemptProjectsintooling/testing/coverage-policy.jsondürfen deshalb nicht im Codecov-Flagunittestsauftauchen. - Der lokale Preview-Check
pnpm patch-coverage-gate --base=origin/mainnutzt denselben Workspace-Scope wie unsere interne Coverage-Governance, damit Abweichungen vor dem Push sichtbar werden. - Lokale
src/*.js,src/*.d.tsodersrc/*.d.ts.mapin Paketen verfälschen Import-Auflösung undlcov-Pfadzuordnung. Vor Coverage-Debugging deshalbpnpm clean:generated-source-artifactsundpnpm check:file-placementausführen.
Aktuell als coverage-exempt markiert:
- keine Projekte
Neue Exemptions sind nur in begründeten Ausnahmefällen zulässig und müssen in tooling/testing/coverage-policy.json dokumentiert werden.
- Prüfen, ob Änderungen ein exemptes Projekt betreffen.
- Prüfen, ob mindestens
lintim betroffenen Projekt erfolgreich war. - Prüfen, ob angrenzende nicht-exempte Projekte (z. B.
auth-runtime,sdk,monitoring-client) grünetest:unit-Runs haben. - Bei funktionalen Änderungen in exempten Projekten: expliziten Test-Nachweis im PR verlangen (mindestens Smoke/Contract-Run), bis die Exemption entfernt ist.
-
auth-runtime: echtertest:unit-Run via Vitest -
sdk: echtertest:unit-Run via Vitest -
monitoring-client: echtertest:unit-Run via Vitest -
sva-studio-react: echtertest:unit-Run via Vitest (--passWithNoTests)
-
auth-runtime:test:coveragevia Vitest (--coverage) -
routing:test:coveragevia Vitest (--coverage) -
sdk:test:coveragevia Vitest (--coverage) -
monitoring-client:test:coveragevia Vitest (--coverage) -
sva-studio-react:test:coveragevia Vitest (--coverage)
Die Merge-Checkliste für Coverage-Nachweise steht unter ../reports/PR_CHECKLIST.md.
Policy und Floors liegen in ../../tooling/testing/coverage-policy.json.
Die ergänzende Komplexitäts-Governance steht unter ./complexity-quality-governance.md.
Symptom: pnpm test:coverage:affected läuft durch, aber es wird keine Coverage generiert (keine coverage/coverage-summary.json).
Häufige Ursachen:
- Es gibt tatsächlich keine betroffenen Projekte mit
test:coverageTarget. -
origin/mainist lokal nicht aktuell (falsche--baseReferenz).
Vorgehen:
git fetch origin main
pnpm test:coverage:affectedDebugging:
pnpm nx affected --target=test:coverage --base=origin/main --head=HEAD --verboseWenn der PR Änderungen enthält, aber kein Projekt als betroffen erkannt wird, prüfe:
- ob die Änderung in einem Nx-Projekt liegt (nicht z. B. nur in nicht-erfassten Ordnern)
- ob das betroffene Projekt überhaupt ein
test:coverageTarget definiert
Symptom: Das Coverage-Gate meldet, dass coverage-summary.json fehlt.
Häufige Ursachen:
- Coverage ist im Projekt nicht konfiguriert (z. B.
@vitest/coverage-v8fehlt). -
test:coveragewird ohne Coverage-Flag/Reporter ausgeführt. - Es existieren keine Tests (siehe „No tests configured“).
Vorgehen:
- Sicherstellen, dass Coverage-Dependency installiert ist (pro Projekt):
pnpm --filter <project> add -D @vitest/coverage-v8
-
test:coveragelokal laufen lassen:pnpm nx run <project>:test:coverage
- Prüfen, ob im Projektverzeichnis
coverage/coverage-summary.jsonundcoverage/lcov.infoerzeugt werden.
Symptom: Das Gate schlägt fehl, weil eine Metrik im Vergleich zur Baseline um mehr als die erlaubten Prozentpunkte gefallen ist.
Vorgehen:
- Primär: Tests ergänzen oder bestehende Tests reparieren, bis die Regression behoben ist.
- Falls die Baseline bewusst angepasst werden soll (z. B. Refactor mit geänderter Messbasis): Baseline nur nach Team-Entscheid aktualisieren:
pnpm coverage-gate --update-baseline
Hinweis: Baseline-Updates sind kein Ersatz für fehlende Tests.
Symptom: Das Gate meldet hotspot <datei> <metrik> below floor.
Ursache: Eine in criticalProjects.<projekt>.hotspotFloors definierte kritische Datei liegt unter dem Mindestwert für lines, functions oder branches.
Vorgehen:
- Tests gezielt für den betroffenen Hotspot ergänzen
- Falls der Hotspot durch neue Komplexität entstanden ist: Komplexitäts-Review und ggf. neue Refactoring-Aufgabe ergänzen
- Floors nur anheben oder feiner zuschneiden, nie wegen steigender Komplexität absenken
Symptom: Ein Projekt taucht nicht im Gate-Report auf oder beeinflusst die „global“ Auswertung nicht.
Ursache: Das Projekt ist in tooling/testing/coverage-policy.json unter exemptProjects gelistet.
Vorgehen:
- Exemption nur temporär nutzen.
- Sobald Unit-Tests vorhanden sind:
- Projekt aus
exemptProjectsentfernen - Floors (z. B. unter
perProjectFloors) setzen - Baseline aktualisieren (Team-Entscheid)
- Projekt aus
Symptom: Test-Run ist „grün“, aber es werden keine Coverage-Artefakte erzeugt.
Häufige Ursache: Es gibt keine Testdateien im Projekt; je nach Konfiguration kann --passWithNoTests den Run trotzdem erfolgreich beenden.
Vorgehen:
- Mindestens einen Unit-Test hinzufügen (damit Coverage erzeugt wird).
- Optional (je nach Governance-Entscheid):
--passWithNoTestsentfernen, damit fehlende Tests früh sichtbar werden.
- Dependencies für Tests und Coverage installieren:
pnpm --filter <package-name> add -D vitest @vitest/coverage-v8
- Nx Targets im
project.jsonergänzen:test:unittest:coverage
- Mindestens einen Unit-Test anlegen:
mkdir -p packages/<package-dir>/tests
- Policy aktualisieren:
- Projekt aus
exemptProjectsintooling/testing/coverage-policy.jsonentfernen - Optional
perProjectFloors.<project>setzen
- Projekt aus
- Baseline neu erzeugen:
pnpm test:coverage pnpm coverage-gate --update-baseline
- Validierung lokal ausführen:
pnpm nx run <project>:test:coverage COVERAGE_GATE_REQUIRE_SUMMARIES=1 pnpm coverage-gate
# Alle Coverage-Targets
pnpm test:coverage
# Nur betroffene Coverage-Targets
pnpm test:coverage:affected
# Gate lokal prüfen
pnpm coverage-gate- Coverage Policy:
../../tooling/testing/coverage-policy.json - Coverage Baseline:
../../tooling/testing/coverage-baseline.json - Komplexitäts-Policy:
../../tooling/quality/complexity-policy.json - Komplexitäts-Baseline:
../../tooling/quality/complexity-baseline.json - Komplexitäts-Governance:
./complexity-quality-governance.md - PR-Checklist:
../reports/PR_CHECKLIST.md