# MeshiTrack Web Test Coverage Implementation Plan This blueprint outlines the systematic plan to bridge the remaining test coverage gaps in `@meshitrack/web` (currently at **94.45% Line / 83.61% Branch** coverage). By resolving these minor gaps, we will achieve a pristine, 100%-validated web architecture, mirroring the excellence of `@meshitrack/api` and `@meshitrack/shared`. --- ## 📊 Current State Analysis & Gap Identification Our recent monorepo health check has pinpointed a highly consistent pattern of minor coverage gaps. Almost all uncovered branches stem from optional parameter handling (falsy pathways) and network boundary error tolerances. ```mermaid graph TD A[Web Coverage Gaps] --> B[1. Core API Services - 99.28%] A --> C[2. Real-Time WebSocket - 97.82%] A --> D[3. Interactive UI & Layout - 94.87%] A --> E[4. Next.js Pages - 90-98%] B --> B1[Falsy Query Parameters & Auth headers] C --> C1[Early returns, Max reconnect attempts, Falsy event reasons] D --> D1[Dynamic avatar falls, Toggle states, Sidebar active routes] E --> E1[Empty lists, Loading fallbacks, Pricing permutations] ``` --- ## 🛠️ Step-by-Step Execution Plan ### Phase 1: Core API Services & Client (Target: 100% Coverage) The API services layer has reached **99.28%** coverage. We will close the final **0.72%** gap by testing standard fallback branches for optional query objects. #### 1.1 `services/api-client.ts` (Current: 93.10% Lines / 92.85% Branches) * **Gap**: The `.baseUrl` getter is never called, and `apiClient.delete` is never tested with an authenticated session token. * **TDD Solution**: * Write a test asserting that `apiClient.baseUrl` matches the configured environment URL. * Write an integration test for `apiClient.delete` verifying that the `Authorization` header is correctly injected when `apiClient.accessToken` is set. #### 1.2 `services/purchases.ts` (Current: 93.75% Statements / 90.00% Branches) * **Gap**: The `cursor` query parameter on line 24 is never passed or verified in search results. * **TDD Solution**: * Expand `listPurchases builds query string` test in `purchases.test.ts` to include a `{ cursor: 'curr-123' }` argument, expecting `cursor=curr-123` in the generated endpoint path. #### 1.3 `services/refills.ts` (Current: 92.85% Branches) * **Gap**: `listRefillLists` is never tested without its optional query parameter, leaving the falsy `query` coalescing branch uncovered. * **TDD Solution**: * Add a unit test `listRefillLists with no query` in `refills.test.ts` asserting that the query string is omitted entirely when no arguments are provided. #### 1.4 `services/shopping-lists.ts` (Current: 75.00% Branches) * **Gap**: `getShoppingListSyncSocketUrl` is never tested with an empty/falsy `apiClient.baseUrl`, leaving the default string fallback branch untested. * **TDD Solution**: * Add a test setting `apiClient.baseUrl = ''` and verify the socket URL resolves cleanly to `ws:///households/...`. #### 1.5 `services/medicines.ts` & `services/cabinet-events.ts` * **Gap**: `listMedicineProducts` and `getEventsByItem` are never tested without query objects. * **TDD Solution**: * Add clean unit tests verifying that both functions omit parameters entirely when passed only their mandatory IDs. --- ### Phase 2: Collaborative Real-Time Sync (Target: 100% Coverage) The custom WebSocket hook `useShoppingListSync.ts` handles collaborative syncing. It has four remaining uncovered branches on lines 22, 56-59, and 86. ```typescript // useShoppingListSync.ts Uncovered Branches if (!householdId || !listId) return; // 1. Early Return ws.onclose = (event) => { console.log(`🔌 Sync severed: ${event.reason || 'Disconnected'}`); // 2. Falsy Event Reason if (reconnectAttemptsRef.current < 5) { ... } // 3. Exhausted Reconnect boundary }; if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) { ... } // 4. Closed Socket Send Attempts ``` #### TDD Solution: 1. **Early Return**: Write a hook unit test passing an empty string `""` for `listId` and assert that the hook does not instantiate a WebSocket connection. 2. **Falsy Event Reason**: Close the mocked WebSocket connection without providing a closure reason, and assert that the hook safely logs `'Disconnected'` without runtime crashes. 3. **Exhausted Reconnect**: Mock 5 consecutive WebSocket connection closures, advance the test timers using `vi.useFakeTimers()`, and assert that the hook ceases to make a 6th reconnection handshake. 4. **Closed Socket Send**: Invoke `toggleItemCheck` when the mocked socket is in `WebSocket.CLOSED` state, and verify that the hook skips calling `.send` entirely. --- ### Phase 3: Interactive UI Components (Target: 100% Coverage) Interactive UI helpers (`Avatar.tsx`, `Icon.tsx`, `Sidebar.tsx`, `TopBar.tsx`) are currently at **94.87%** branch coverage. We will exercise the rare edge cases where layout values are undefined. * **Avatar**: Test rendering the component without an image source or name, ensuring it falls back safely to a default generic avatar layout. * **Icon**: Pass an unknown/invalid icon name to verify the component fails gracefully or falls back to a clean default glyph rather than throwing a crash. * **Sidebar / TopBar**: Assert active routes and toggle hamburger menu states when users reside on nested directories vs. core root settings. --- ### Phase 4: Next.js Dashboard Pages (Target: >95% Coverage) Page-level integration tests (`shopping-lists/page.tsx`, `[id]/page.tsx`, `prices/page.tsx`, `stores/page.tsx`) will be upgraded to assert full application layouts: * **Empty States**: Render the page with an empty list array resolved from MSW, and assert that a descriptive "No shopping lists found" prompt is present. * **Loading Boundaries**: Capture SWR's `isValidating` or `isLoading` states, and assert that a skeleton card loader is visible. * **Failure Interception**: Force MSW to return a 500 error, and assert that the error notification banner renders correctly to prevent silent UI failures. --- ## 🚀 TDD Feedback Loop To make this execution fast, smooth, and interactive, we will use our customized watch command. This enables instant feedback when writing the new tests: ```bash # Watch the web package continuously npm run test:watch -w packages/web # Focus specifically on one service test during Phase 1 npm run test:watch -w packages/web -- tests/services/shopping-lists.test.ts ``` > [!TIP] > Resolving these specific gaps will yield a robust frontend architecture. This coverage guarantees that subsequent visual designs and functional refactors can be committed safely with absolute confidence.