Full tests coverage
This commit is contained in:
parent
99134d8556
commit
02d782c3da
157 changed files with 1074 additions and 34670 deletions
113
docs/web_test_coverage_plan.md
Normal file
113
docs/web_test_coverage_plan.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue