You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
10 KiB
Markdown
262 lines
10 KiB
Markdown
# 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)
|