# Test Plan E5.S2 - Error Handling **Datum:** 27-12-2024 **Status:** Ready for Testing **Story:** E5.S2 - Error handling (2 SP) --- ## ✅ Implementatie Overzicht ### Nieuwe bestanden: 1. **`lib/swift/error-handler.ts`** - Error handling utility met: - `isOffline()` - Detect browser offline status - `isNetworkError()` - Network error detection - `isTimeoutError()` - Timeout detection - `parseErrorResponse()` - Parse HTTP error responses - `getErrorInfo()` - Generate user-friendly error messages - `safeFetch()` - Fetch wrapper met timeout (30s) - `retryFetch()` - Retry logic met exponential backoff 2. **`components/swift/command-center/offline-banner.tsx`** - Offline banner component - Toont amber banner bij `!navigator.onLine` - `useOffline()` hook voor offline detection ### Geüpdatete bestanden: 1. **`components/swift/command-center/command-center.tsx`** - OfflineBanner geïntegreerd 2. **`components/swift/command-center/command-input.tsx`** - Error handling met safeFetch/getErrorInfo 3. **`components/swift/command-center/context-bar.tsx`** - useOffline hook voor margin adjustment 4. **`components/swift/blocks/dagnotitie-block.tsx`** - safeFetch, getErrorInfo, retryFetch 5. **`components/swift/blocks/zoeken-block.tsx`** - safeFetch, getErrorInfo 6. **`components/swift/blocks/overdracht-block.tsx`** - safeFetch, getErrorInfo, retryFetch --- ## 🧪 Test Scenarios ### 1. Offline Detection ✅ **Test 1.1: Browser Offline** - [ ] Open DevTools → Network tab → Throttling → Offline - [ ] Amber banner verschijnt bovenaan: "Geen internetverbinding" - [ ] Context bar heeft `marginTop: 40px` (geen overlap) - [ ] Try een actie (dagnotitie opslaan, patient zoeken) - [ ] Toast shows: "Geen internetverbinding - Controleer je internetverbinding en probeer het opnieuw." **Test 1.2: Reconnect** - [ ] Zet network weer op "Online" - [ ] Banner verdwijnt automatisch - [ ] Context bar margin reset - [ ] Acties werken weer normaal --- ### 2. Network Errors **Test 2.1: API Endpoint Down** - [ ] Stop de dev server (kill process) - [ ] Probeer dagnotitie opslaan - [ ] Toast shows: "Verbinding verbroken - Kon geen verbinding maken met de server." - [ ] Retry button beschikbaar (voor retryable errors) **Test 2.2: Timeout (30s)** - [ ] Simuleer slow API (add `await new Promise(r => setTimeout(r, 35000))` in API route) - [ ] Probeer actie - [ ] Na 30 seconden: Toast shows "Verbinding timeout" --- ### 3. HTTP Status Codes **Test 3.1: 401 Unauthorized** - [ ] Simuleer 401 in API route: `return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })` - [ ] Toast shows: "Niet geautoriseerd - Je sessie is verlopen. Log opnieuw in." - [ ] `retryable: false` (geen retry button) **Test 3.2: 404 Not Found** - [ ] Probeer non-existent patient ID: `/api/fhir/Patient/99999999` - [ ] Toast shows: "Niet gevonden - Patiënt data ophalen niet gevonden." **Test 3.3: 400 Bad Request** - [ ] Submit dagnotitie zonder required fields - [ ] Toast shows: "Ongeldige aanvraag - [validation message]" **Test 3.4: 500 Internal Server Error** - [ ] Simuleer server error in API route: `throw new Error('DB error')` - [ ] Toast shows: "Serverfout - Er ging iets mis op de server. Probeer het later opnieuw." - [ ] `retryable: true` **Test 3.5: 429 Too Many Requests** - [ ] (Moeilijk te simuleren zonder rate limiter) - [ ] Toast should show: "Te veel aanvragen - Wacht even en probeer het later opnieuw." --- ### 4. Validation Errors **Test 4.1: Empty Fields in DagnotatieBlock** - [ ] Open dagnotitie block - [ ] Klik "Opslaan" zonder patiënt - [ ] Toast shows: "Validatiefout - Selecteer een patiënt" - [ ] Klik "Opslaan" zonder categorie - [ ] Toast shows: "Validatiefout - Selecteer een categorie" - [ ] Klik "Opslaan" zonder tekst - [ ] Toast shows: "Validatiefout - Voer een notitie in" **Test 4.2: Search Query Too Short** - [ ] Type "j" in ZoekenBlock (< 2 characters) - [ ] Geen API call (debounced + min length check) --- ### 5. Intent Classification Errors **Test 5.1: API Error** - [ ] Typ commando in command input - [ ] Simuleer API error in `/api/intent/classify` - [ ] Toast shows error message - [ ] FallbackPicker opent automatisch met original input - [ ] Input is niet verloren (preserved in FallbackPicker) **Test 5.2: Low Confidence** - [ ] Typ gibberish: "asdfasdf jkljkl" - [ ] Confidence < 0.5 - [ ] FallbackPicker opent met original input - [ ] Can select fallback action (dagnotitie, zoeken, overdracht) --- ### 6. Retry Logic **Test 6.1: Retry Success on 2nd Attempt** - [ ] Simuleer intermittent error (fails first, succeeds second) - [ ] DagnotatieBlock save with `retryFetch()` - [ ] Should retry automatically (max 3 attempts) - [ ] Success toast after retry succeeds **Test 6.2: Retry Exhausted (3 failures)** - [ ] Simuleer consistent error (always fails) - [ ] After 3 retries: Final error toast shown - [ ] No infinite retry loop --- ### 7. User-Friendly Messages (Dutch) **Test 7.1: All Error Messages in Dutch** - [ ] Check all toast messages are in Dutch - [ ] Check all error titles are in Dutch - [ ] No English fallback messages visible to user **Test 7.2: Error Message Quality** - [ ] Messages are actionable ("Controleer je internetverbinding") - [ ] Not technical jargon ("fetch failed" → "Verbinding verbroken") - [ ] Clear next steps when applicable --- ### 8. Edge Cases **Test 8.1: HTML Error Response (Auth Redirect)** - [ ] Simulate HTML response (login page redirect) - [ ] `parseErrorResponse()` detects HTML - [ ] Toast shows: "Niet geautoriseerd. Log opnieuw in." **Test 8.2: Malformed JSON Response** - [ ] Simulate invalid JSON from API - [ ] Error handled gracefully (no crash) - [ ] User-friendly error shown **Test 8.3: Error During Voice Input** - [ ] Start voice recording - [ ] Trigger error (offline, etc.) - [ ] Voice recording stops gracefully - [ ] Error shown to user --- ## ✅ Implementation Checklist - [x] `lib/swift/error-handler.ts` created with all utilities - [x] `components/swift/command-center/offline-banner.tsx` created - [x] OfflineBanner integrated in CommandCenter - [x] CommandInput uses safeFetch + getErrorInfo - [x] ContextBar uses useOffline hook (margin adjustment) - [x] DagnotatieBlock uses safeFetch + getErrorInfo + retryFetch - [x] ZoekenBlock uses safeFetch + getErrorInfo - [x] OverdrachtBlock uses safeFetch + getErrorInfo + retryFetch - [x] All error messages in Dutch - [x] FallbackPicker handles unknown intents gracefully - [x] TypeScript compiles without errors --- ## 📋 Manual Testing Checklist (Quick Smoke Test) Voor snelle verificatie: 1. **Offline Mode:** - [ ] DevTools → Offline → Banner appears → Try action → Error toast 2. **Network Error:** - [ ] Stop server → Try action → Error toast with retry 3. **Validation Error:** - [ ] Submit empty dagnotitie → Validation toast 4. **Intent Error:** - [ ] Type gibberish → FallbackPicker opens 5. **Success Path:** - [ ] Online → Submit dagnotitie → Success toast → Block closes --- ## 🎯 Acceptatie Criteria E5.S2 - [x] Network errors tonen user-friendly messages (Dutch) - [x] Offline detection met visual indicator (banner) - [x] Validation errors zijn duidelijk en actionable - [x] Retry functionaliteit werkt voor transient errors - [x] HTTP status codes mapped naar begrijpelijke messages - [x] FallbackPicker shown on intent classification failure - [x] No lost user input on errors (preserved in FallbackPicker) - [x] All error scenarios from test-plan-epic3.md covered --- ## 🚀 Status **E5.S2 - Error Handling: COMPLETE ✅** All error handling utilities implemented, integrated across all components, and ready for testing.