# Test Report – T04: Kontakt-/Kundenverwaltung + Contact UI ## Backend Tests **Command:** `cd backend && python -m pytest tests/test_contacts.py --cov=app.routers.contacts --cov=app.services.contact_service --cov=app.utils.ust_validation --cov=app.models.contact --cov=app.schemas.contact --cov-report=term-missing -v` **Result:** 73 passed, 0 failed ### Coverage | Module | Stmts | Miss | Cover | |--------|-------|------|-------| | app/models/contact.py | 55 | 4 | 93% | | app/routers/contacts.py | 51 | 17 | 67% | | app/schemas/contact.py | 98 | 6 | 94% | | app/services/contact_service.py | 100 | 1 | 99% | | app/utils/ust_validation.py | 31 | 2 | 94% | | **TOTAL** | **335** | **30** | **91%** | **Coverage target:** >= 80% → **PASSED (91%)** ### Test Categories - **TestUstValidation** (13 tests): DE/EU VAT ID format validation, edge cases - **TestContactList** (10 tests): Pagination, role filter (beide included), is_eu filter, search, sort - **TestContactDetail** (3 tests): Detail with contact persons, 404 for nonexistent, 404 after soft-delete - **TestContactCreate** (7 tests): Valid create, invalid VAT ID 422, missing fields 422, nested contact persons - **TestContactUpdate** (4 tests): Valid update, 404 nonexistent, invalid VAT 422, no fields 400 - **TestContactDelete** (3 tests): Soft-delete, 404 nonexistent, not in list after delete - **TestContactPersons** (5 tests): Add person, remove person, 404 cases, detail includes persons - **TestContactRBAC** (12 tests): Auth required, admin+verkaeufer write, verkaeufer read, all endpoints RBAC - **TestContactServiceDirect** (16 tests): Direct service-level coverage for all functions ## Frontend Tests **Command:** `cd frontend && npx vitest run tests/contacts.test.tsx` **Result:** 20 passed, 0 failed ### Test Categories - **ContactList** (5 tests): Renders table with search/filter, displays contacts, new contact button, error handling, loading state - **ContactForm** (7 tests): All fields rendered, EU/Inland toggle, defaults to DE, VAT ID validation, valid submission, required fields - **validateVatIdFormat** (8 tests): DE/AT/NL valid, invalid DE, non-EU country, lowercase, spaces ## Smoke Test - Backend: All 7 API endpoints tested via HTTPX ASGI transport with real PostgreSQL test database - Frontend: Component rendering tested with jsdom, API calls mocked - RBAC: admin and verkaeufer roles tested for all write endpoints - Soft-delete: Verified deleted contacts return 404 and don't appear in list - VAT ID validation: Both backend (Pydantic field_validator) and frontend (validateVatIdFormat) tested ## Acceptance Criteria Verification | Criterion | Status | Evidence | |-----------|--------|----------| | GET /api/v1/contacts → 200 + paginated list | ✅ | test_list_contacts_returns_200_with_pagination | | GET /api/v1/contacts?role=kaeufer → filtered (beide included) | ✅ | test_list_contacts_filter_by_role_kaeufer_includes_beide | | GET /api/v1/contacts?is_eu=true → EU contacts only | ✅ | test_list_contacts_filter_is_eu_true | | GET /api/v1/contacts?search=mueller → matching contacts | ✅ | test_list_contacts_search_by_company_name | | GET /api/v1/contacts/:id → detail with contact persons | ✅ | test_get_contact_returns_200_with_detail | | GET /api/v1/contacts/:nonexistent → 404 | ✅ | test_get_contact_nonexistent_returns_404 | | POST /api/v1/contacts valid → 201 | ✅ | test_create_contact_returns_201 | | POST /api/v1/contacts invalid vat_id → 422 | ✅ | test_create_contact_with_invalid_vat_id_returns_422 | | PUT /api/v1/contacts/:id → 200 + updated | ✅ | test_update_contact_returns_200 | | DELETE /api/v1/contacts/:id → 200 (soft delete) | ✅ | test_delete_contact_returns_200 | | Frontend Contact List renders table with search + filter | ✅ | renders contact list with search and filter controls | | Frontend Contact Form validates USt-IdNr. format | ✅ | validates VAT ID format and shows error for invalid DE VAT | | Frontend EU/Inland toggle changes required fields | ✅ | switches to EU mode and shows VAT ID hint when EU is selected | | pytest coverage >= 80% contact module | ✅ | 91% total coverage |