Add test coverage and documentation improvement spec
Addresses all 5 recommendations from tech lead assessment: - Frontend page tests (~39 tests for Settings, Home, Sources, Login, Generate) - Frontend JSDoc documentation (~30 files) - Backend test gaps (schema builder, auth middleware, token utils) - E2E tests with Playwright (5 flows against real Docker stack) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>master
parent
98528f51bd
commit
449edfcf59
@ -0,0 +1,261 @@
|
||||
# Design: Test Coverage & Documentation Improvements
|
||||
|
||||
**Date**: 2026-03-22
|
||||
**Source**: docs/tech_lead_assessment_Coverage_Documentation.md
|
||||
**Scope**: 5 improvements — frontend page tests, frontend JSDoc, backend test gaps, E2E tests
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
The tech lead assessment graded the backend A (332 unit + 145 integration tests, good documentation) and the frontend C (103 utility/API tests only, weak documentation). Every page and component has zero test coverage. This design addresses all 5 recommendations from the assessment.
|
||||
|
||||
---
|
||||
|
||||
## 1. Frontend Component/Page Tests
|
||||
|
||||
### Goal
|
||||
Add interaction-level tests for the 5 most critical pages using `@solidjs/testing-library` + Vitest + MSW.
|
||||
|
||||
### Test Infrastructure
|
||||
- **MSW (Mock Service Worker)** to intercept fetch calls in tests
|
||||
- **Shared `test-utils.ts`** with a `renderWithProviders()` helper that wraps components in AuthContext, I18nProvider, ToastProvider, and Router
|
||||
- **Mocked Turnstile** — stub `window.turnstile` in test setup
|
||||
- **Mocked EventSource** — stub for SSE tests in GenerateSynthesis
|
||||
|
||||
### Pages and Tests (~39 tests)
|
||||
|
||||
#### Settings.tsx (~10 tests)
|
||||
- Renders form with all fields populated from API response
|
||||
- Save button calls PUT /settings with form data
|
||||
- Provider dropdown populated from config API
|
||||
- Selecting provider updates model dropdown options
|
||||
- Dual model dropdowns render (research + writing)
|
||||
- Rate limit section renders with null values (empty inputs)
|
||||
- Rate limit section shows effective rate when values set
|
||||
- Reset link clears rate limit fields to null
|
||||
- Export downloads JSON file
|
||||
- Import populates form from uploaded JSON
|
||||
|
||||
#### Home.tsx (~7 tests)
|
||||
- Renders synthesis list from API response
|
||||
- Empty state shows when no syntheses
|
||||
- "Nouvelle Synthese" button links to /generate
|
||||
- Delete first click shows "Confirmer" state
|
||||
- Delete second click removes synthesis from list
|
||||
- Delete auto-cancels after 3 seconds
|
||||
- In-progress banner shows when a synthesis has status "in_progress"
|
||||
|
||||
#### Sources.tsx (~8 tests)
|
||||
- Renders source list from API response
|
||||
- Empty state shows when no sources
|
||||
- Add form validates empty title/URL
|
||||
- Add form submits and new source appears in list
|
||||
- Delete with confirmation removes source
|
||||
- Bulk import textarea parses and imports
|
||||
- CSV export triggers download
|
||||
- CSV import triggers file picker
|
||||
|
||||
#### Login.tsx + Register.tsx (~8 tests)
|
||||
- Login renders email input and submit button
|
||||
- Login submit calls POST /auth/login
|
||||
- Login shows "check inbox" message on success
|
||||
- Login shows error on API failure
|
||||
- Resend button disabled during cooldown
|
||||
- Register renders email + display name + submit
|
||||
- Register submit calls POST /auth/register
|
||||
- Register shows confirmation on success
|
||||
|
||||
#### GenerateSynthesis.tsx (~6 tests)
|
||||
- Renders launch button with settings info
|
||||
- Launch button calls POST /syntheses/generate
|
||||
- Progress bar updates from SSE events
|
||||
- Step checklist shows done/in-progress/pending states
|
||||
- Completion redirects to synthesis detail
|
||||
- Error state shows retry button
|
||||
|
||||
### Dependencies to Add
|
||||
- `msw` (dev dependency) for API mocking
|
||||
- No other new dependencies needed (`@solidjs/testing-library` already installed)
|
||||
|
||||
---
|
||||
|
||||
## 2. Frontend JSDoc Documentation
|
||||
|
||||
### Goal
|
||||
Add English JSDoc comments to all exported components, functions, and complex logic blocks. No code changes.
|
||||
|
||||
### Scope
|
||||
|
||||
#### API Layer
|
||||
- `api/client.ts` — class purpose, CSRF strategy (`X-Requested-With`), credential handling (`same-origin`), 401 redirect behavior
|
||||
- `api/auth.ts`, `api/settings.ts`, `api/sources.ts`, `api/syntheses.ts`, `api/admin.ts`, `api/config.ts`, `api/apiKeys.ts` — brief JSDoc on each exported function
|
||||
|
||||
#### Pages (complex logic)
|
||||
- `pages/Settings.tsx` — export/import logic, provider auto-detection, rate limit null handling, dual model state management
|
||||
- `pages/GenerateSynthesis.tsx` — SSE state machine (idle -> connecting -> progress -> complete/error), step progression, reconnection, completion redirect timer
|
||||
- `pages/Home.tsx` — delete confirmation timer pattern (first click -> confirm state -> 3s auto-cancel)
|
||||
- `pages/Sources.tsx` — bulk import parsing, CSV import/export flow, URL normalization
|
||||
- `pages/SynthesisDetail.tsx` — email send flow, file download mechanism (Blob + anchor)
|
||||
- `pages/Login.tsx`, `pages/Register.tsx` — Turnstile lifecycle, resend cooldown timer
|
||||
- `pages/AuthVerify.tsx` — token extraction from URL, verification flow
|
||||
|
||||
#### Components
|
||||
- `components/ApiKeyManager.tsx` — key CRUD flow, show/hide toggle, test button
|
||||
- `components/Turnstile.tsx` — widget lifecycle, polling initialization, cleanup
|
||||
- `components/Navbar.tsx` — active route detection, admin link visibility
|
||||
- `components/MobileMenu.tsx` — escape key handler, backdrop click
|
||||
- `components/Layout.tsx`, `components/AdminLayout.tsx` — layout structure, sidebar nav
|
||||
- `components/ErrorBoundary.tsx` — error catching, retry mechanism
|
||||
- `components/ui/Button.tsx` — props interface, variant behavior (primary/secondary/danger)
|
||||
- `components/ui/Toast.tsx` — toast provider pattern, auto-dismiss timer
|
||||
- `components/ui/LoadingSpinner.tsx` — size/fullPage props
|
||||
|
||||
#### Utilities
|
||||
- `utils/sse.ts` — reconnection backoff logic (exponential, max 3 retries), event type parsing, cleanup
|
||||
- `utils/dates.ts` — date-fns locale configuration
|
||||
- `utils/providers.ts` — provider capability detection
|
||||
|
||||
#### Context
|
||||
- `contexts/AuthContext.tsx` — session check on mount, 401 handling, isAdmin derived signal
|
||||
|
||||
### Style
|
||||
- Brief `/** ... */` on exports
|
||||
- Inline `//` comments only for non-obvious logic (state machines, timers, edge cases)
|
||||
- No boilerplate comments on trivial code (simple getters, obvious props)
|
||||
|
||||
---
|
||||
|
||||
## 3. Backend Test Gaps
|
||||
|
||||
### 3a. Schema Builder Tests (`services/llm/schema.rs`) — 6 tests
|
||||
- `test_schema_single_category` — 1 category produces `category_0` with correct item schema
|
||||
- `test_schema_five_categories` — 5 categories produce `category_0` through `category_4`
|
||||
- `test_schema_twenty_categories` — max 20 categories all present
|
||||
- `test_schema_special_characters` — category names with accents, quotes, ampersands don't break JSON
|
||||
- `test_schema_long_category_name` — 200-char category name accepted
|
||||
- `test_schema_item_structure` — each category value is array of `{title: string, url: string, summary: string}`
|
||||
|
||||
### 3b. Auth Middleware Unit Tests (`middleware/auth.rs`) — 5 tests
|
||||
- `test_valid_session_cookie_extracted` — properly formatted cookie returns token
|
||||
- `test_malformed_cookie_no_equals` — cookie without `=` returns None
|
||||
- `test_missing_cookie_header` — no Cookie header returns Unauthorized
|
||||
- `test_multiple_cookies_correct_one_picked` — session cookie found among other cookies
|
||||
- `test_cookie_with_whitespace` — leading/trailing whitespace trimmed
|
||||
|
||||
### 3c. Token Utility Tests (`util/token.rs`) — 4 tests
|
||||
- `test_generated_token_length` — base64url-encoded token has expected length
|
||||
- `test_tokens_are_unique` — two consecutive generated tokens differ
|
||||
- `test_hash_is_deterministic` — same input produces same hash
|
||||
- `test_hash_differs_from_raw` — hash output is not the raw token
|
||||
|
||||
**Total: 15 new backend unit tests**, bringing count from 332 to ~347.
|
||||
|
||||
---
|
||||
|
||||
## 4. E2E Tests with Playwright
|
||||
|
||||
### Infrastructure
|
||||
|
||||
**`e2e/docker-compose.test.yml`:**
|
||||
- Extends main `docker-compose.yml`
|
||||
- Uses a test-specific Postgres database (fresh per run)
|
||||
- App service with `TEST_DATABASE_URL` and test Turnstile/Resend keys
|
||||
- Exposes app on port 8080
|
||||
|
||||
**`e2e/seed.ts`:**
|
||||
- Node.js script connecting directly to test Postgres
|
||||
- Creates admin user (email_verified, role=admin) with a known session token
|
||||
- Creates regular test user with a known session token
|
||||
- Both sessions have 30-day expiry
|
||||
|
||||
**`e2e/helpers/auth.ts`:**
|
||||
- `loginAsAdmin()` — sets session cookie for admin
|
||||
- `loginAsUser()` — sets session cookie for regular user
|
||||
- `registerAndVerify(email)` — inserts magic link token in DB, navigates to verify URL
|
||||
- Direct DB access via `pg` npm package for token extraction
|
||||
|
||||
**`e2e/playwright.config.ts`:**
|
||||
- Base URL: `http://localhost:8080`
|
||||
- Timeout: 30s per test
|
||||
- Retries: 1
|
||||
- Screenshots on failure
|
||||
|
||||
### Test Flows (5 specs)
|
||||
|
||||
#### `registration.spec.ts`
|
||||
- Navigate to /register
|
||||
- Fill email, submit (Turnstile bypassed via test key)
|
||||
- Extract magic link token from DB
|
||||
- Navigate to /auth/verify?token=...
|
||||
- Assert: redirected to Home, user email shown in navbar
|
||||
|
||||
#### `admin-providers.spec.ts`
|
||||
- Login as admin (cookie injection)
|
||||
- Navigate to /admin/providers
|
||||
- Enable Gemini provider, add a model
|
||||
- Save
|
||||
- Assert: provider appears in GET /config/providers response
|
||||
|
||||
#### `settings.spec.ts`
|
||||
- Login as user
|
||||
- Navigate to /settings
|
||||
- Change theme, select provider + models, save
|
||||
- Reload page
|
||||
- Assert: all saved values repopulated
|
||||
|
||||
#### `sources.spec.ts`
|
||||
- Login as user
|
||||
- Navigate to /sources
|
||||
- Add a source (title + URL)
|
||||
- Bulk import 3 sources
|
||||
- Assert: 4 sources in list
|
||||
- Delete one
|
||||
- Assert: 3 sources remain
|
||||
- Export CSV
|
||||
- Assert: downloaded file contains 3 rows
|
||||
|
||||
#### `settings-export.spec.ts`
|
||||
- Login as user
|
||||
- Configure settings (theme, categories, models)
|
||||
- Export JSON
|
||||
- Change settings to different values, save
|
||||
- Import the exported JSON
|
||||
- Save
|
||||
- Reload
|
||||
- Assert: original values restored
|
||||
|
||||
### File Structure
|
||||
```
|
||||
e2e/
|
||||
├── playwright.config.ts
|
||||
├── docker-compose.test.yml
|
||||
├── package.json — playwright, pg dependencies
|
||||
├── seed.ts
|
||||
├── helpers/
|
||||
│ └── auth.ts
|
||||
└── tests/
|
||||
├── registration.spec.ts
|
||||
├── admin-providers.spec.ts
|
||||
├── settings.spec.ts
|
||||
├── sources.spec.ts
|
||||
└── settings-export.spec.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Section | New Tests | New Docs | Effort |
|
||||
|---|---|---|---|
|
||||
| Frontend page tests | ~39 | — | Large |
|
||||
| Frontend JSDoc | — | ~30 files | Medium |
|
||||
| Backend test gaps | ~15 | — | Small |
|
||||
| E2E tests | ~5 flows | — | Large |
|
||||
| **Total** | **~59 tests + 5 E2E flows** | **~30 files documented** | |
|
||||
|
||||
### Implementation Order
|
||||
1. Backend test gaps (small, independent, quick win)
|
||||
2. Frontend JSDoc (no code changes, can't break anything)
|
||||
3. Frontend page tests (requires MSW setup first, then tests)
|
||||
4. E2E tests (requires Docker test infrastructure, depends on everything else working)
|
||||
Loading…
Reference in New Issue