feat(T04): contact management + USt-IdNr. validation + contact UI
- Contact model: company, role (kaeufer/verkaeufer/beide), soft-delete - ContactPerson model: 1:N relation with CASCADE delete - USt-IdNr. validation: DE + 10 EU countries - Contact CRUD: 7 API endpoints with RBAC, search/filter/paginate - Frontend: ContactList, ContactForm, ContactDetail with EU/Inland toggle - 73 backend tests (91% coverage), 20 frontend tests
This commit is contained in:
+44
-77
@@ -1,104 +1,71 @@
|
||||
# Test Report – T02: Vehicle Management + mobile.de Push + Vehicle UI
|
||||
|
||||
**Date**: 2026-07-14
|
||||
**Task**: T02
|
||||
**Status**: PASSED
|
||||
# Test Report – T04: Kontakt-/Kundenverwaltung + Contact UI
|
||||
|
||||
## Backend Tests
|
||||
|
||||
**Command**: `cd backend && python -m pytest tests/test_vehicles.py tests/test_mobilede.py tests/test_vehicles_extra.py --cov=app.services.vehicle_service --cov=app.services.mobilede_service --cov=app.routers.vehicles --cov-report=term-missing -v`
|
||||
**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 in 18.84s
|
||||
**Result:** 73 passed, 0 failed
|
||||
|
||||
### Coverage Report
|
||||
### Coverage
|
||||
|
||||
| Module | Stmts | Miss | Cover |
|
||||
|--------|-------|------|-------|
|
||||
| app/routers/vehicles.py | 63 | 25 | 60% |
|
||||
| app/services/mobilede_service.py | 122 | 24 | 80% |
|
||||
| app/services/vehicle_service.py | 86 | 1 | 99% |
|
||||
| **TOTAL** | **271** | **50** | **82%** |
|
||||
| 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% → **MET** (82% total)
|
||||
**Coverage target:** >= 80% → **PASSED (91%)**
|
||||
|
||||
### Test Categories
|
||||
|
||||
#### test_vehicles.py (27 tests)
|
||||
- TestVehicleList: 7 tests (pagination, filter by type/availability/price, sort, search, auth required)
|
||||
- TestVehicleCreate: 6 tests (201 on valid, 422 on missing make/fin/short fin, 409 on duplicate FIN, auto-compute power_hp)
|
||||
- TestVehicleDetail: 2 tests (200 on found, 404 on nonexistent)
|
||||
- TestVehicleUpdate: 3 tests (200 on update, 404 on nonexistent, 400 on no fields)
|
||||
- TestVehicleDelete: 4 tests (200 with deleted_at, 404 on nonexistent, not in list after delete, 404 on detail after delete)
|
||||
- TestMobileDePush: 2 tests (202 on push, 404 on nonexistent vehicle)
|
||||
- TestMobileDeStatus: 3 tests (200 with no listing, 200 with synced listing, 404 on nonexistent)
|
||||
|
||||
#### test_mobilede.py (18 tests)
|
||||
- TestFieldMapping: 8 tests (LKW, Baumaschine, PKW, Stapler, Transporter, no optional fields, lkw_type with prefix, unknown lkw_type fallback)
|
||||
- TestPushListing: 3 tests (success, HTTP error, request error)
|
||||
- TestUpdateListing: 2 tests (success, no ad_id)
|
||||
- TestDeleteListing: 2 tests (success, no ad_id)
|
||||
- TestGetListingStatus: 2 tests (returns latest, returns none)
|
||||
- TestRetryFailedListing: 2 tests (succeeds within max retries, exceeds max retries)
|
||||
|
||||
#### test_vehicles_extra.py (28 tests)
|
||||
- TestVehicleServiceDirect: 21 tests (list empty, pagination, sort asc, invalid sort, min/max price, search by fin/location, get by fin, create, duplicate fin, update, not found, duplicate fin update, same fin, soft delete, not found, get by id not found, excludes deleted)
|
||||
- TestRouterAdditionalPaths: 7 tests (all filters combined, verkaeufer allowed, fin duplicate 409, empty result, invalid UUID 422, push failure 202, status after failed push)
|
||||
- **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/vehicles.test.tsx`
|
||||
**Command:** `cd frontend && npx vitest run tests/contacts.test.tsx`
|
||||
|
||||
**Result**: 16 passed in 2.21s
|
||||
**Result:** 20 passed, 0 failed
|
||||
|
||||
### Test Categories
|
||||
|
||||
#### VehicleList (5 tests)
|
||||
- Renders vehicle list with filters and table
|
||||
- Displays vehicles in table after loading
|
||||
- Shows pagination when total > page_size
|
||||
- Shows error message on API failure
|
||||
- Calls listVehicles with type filter when changed
|
||||
|
||||
#### VehicleForm (4 tests)
|
||||
- Renders form with all required fields
|
||||
- Shows validation errors for empty required fields
|
||||
- Shows error for FIN not 17 characters
|
||||
- Calls createVehicle on submit with valid data
|
||||
|
||||
#### VehicleDetail (3 tests)
|
||||
- Renders vehicle details after loading
|
||||
- Shows mobile.de status section
|
||||
- Shows error message on API failure
|
||||
|
||||
#### MobileDeStatus (4 tests)
|
||||
- Renders with pending status when no listing exists
|
||||
- Shows synced status after successful push
|
||||
- Shows error log when sync failed
|
||||
- Calls pushToMobileDe when push button is clicked
|
||||
- **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 API endpoints tested via HTTPX ASGI transport with real PostgreSQL test DB
|
||||
- Frontend: All components tested with React Testing Library and mocked API calls
|
||||
- mobile.de: All HTTP calls mocked with httpx.AsyncClient patches, no real API calls made
|
||||
- Auth: All vehicle endpoints require JWT Bearer token (verified with 401 test)
|
||||
- Soft-delete: Verified deleted_at is set and vehicle excluded from subsequent queries
|
||||
- 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/vehicles → 200 + paginated list | ✅ | test_list_vehicles_returns_200_with_pagination |
|
||||
| GET /api/v1/vehicles?type=lkw&availability=available → 200 + filtered | ✅ | test_list_vehicles_filter_by_type, test_list_vehicles_filter_by_availability |
|
||||
| GET /api/v1/vehicles?sort=-created_at → 200 + sorted | ✅ | test_list_vehicles_sort_descending |
|
||||
| GET /api/v1/vehicles/:id → 200 + detail, nonexistent → 404 | ✅ | test_get_vehicle_returns_200, test_get_vehicle_nonexistent_returns_404 |
|
||||
| POST /api/v1/vehicles valid → 201, missing make → 422 | ✅ | test_create_vehicle_returns_201, test_create_vehicle_missing_make_returns_422 |
|
||||
| PUT /api/v1/vehicles/:id → 200 + updated | ✅ | test_update_vehicle_returns_200 |
|
||||
| DELETE /api/v1/vehicles/:id → 200 + deleted_at set | ✅ | test_delete_vehicle_returns_200_with_deleted_at |
|
||||
| POST /api/v1/vehicles/:id/mobile-de/push → 202 (async) | ✅ | test_push_returns_202 |
|
||||
| GET /api/v1/vehicles/:id/mobile-de/status → 200 + sync info | ✅ | test_status_returns_200_with_synced_listing |
|
||||
| mobile.de push sends correct Ad format (mocked) | ✅ | test_map_fields_basic_lkw, test_push_listing_success |
|
||||
| Frontend Vehicle List renders table with filter+pagination | ✅ | VehicleList test suite (5 tests) |
|
||||
| Frontend Vehicle Detail shows all fields + mobile.de status | ✅ | VehicleDetail test suite (3 tests) |
|
||||
| Frontend Create Form validates required fields | ✅ | VehicleForm test suite (4 tests) |
|
||||
| pytest coverage >= 80% vehicle module | ✅ | 82% total coverage |
|
||||
| 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 |
|
||||
|
||||
Reference in New Issue
Block a user