From 449edfcf5988e954479ec61a6a86083094de22a7 Mon Sep 17 00:00:00 2001 From: oabrivard Date: Sun, 22 Mar 2026 12:03:49 +0100 Subject: [PATCH] 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) --- ...3-22-test-coverage-documentation-design.md | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-22-test-coverage-documentation-design.md diff --git a/docs/superpowers/specs/2026-03-22-test-coverage-documentation-design.md b/docs/superpowers/specs/2026-03-22-test-coverage-documentation-design.md new file mode 100644 index 0000000..1d6a5d9 --- /dev/null +++ b/docs/superpowers/specs/2026-03-22-test-coverage-documentation-design.md @@ -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)