diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5f25951..6c08f59 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -30,9 +30,13 @@ What changed: Tests: - 11 new unit tests across `pseudonyms.test.ts` (8: FNV determinism, pool integrity per language, in-pool selection, stability, seed-based variation) and `usePseudonym.test.ts` (3: stable across rerenders, regenerate caps at 1, respects language pool). -- 5 new E2E specs in `circulation.spec.ts` covering: home tile visible + labelled bilingually, navigation tile→feed, non-opted-in shows Join CTA (and hides the Share button), feed→settings nav, TTL chooser exposes all three durations. +- 5 new E2E specs in `circulation.spec.ts` covering: home tile visible + labelled bilingually, navigation tile→feed, non-opted-in shows Join CTA (and hides the Share button), feed→settings nav, TTL chooser exposes all three durations. 🟡 Fixed E2E auth mock setup (was timing out before ProtectedRoute); all 5 specs now pass. - `tsc --noEmit` clean. All new vitest tests pass. +**Bug fixes discovered during test validation:** +- 🟡 **E2E test auth setup:** `circulation.spec.ts` was missing `injectMockSession()` and `mockAuthRoutes()`, causing tests to timeout at the home tile (behind ProtectedRoute). Fixed by adding both to beforeEach. +- 🟡 **Language filter missing:** `useLoveLetters.refresh()` had no client-side language filter despite RLS policy comment claiming it enforces language isolation. Added `.eq('language', primaryLang)` for defense-in-depth. Users in different primary languages now correctly see only letters in their language. + **ADHD-Friendly:** - **One thing at a time.** Each screen is single-focus (compose; or browse; or toggle settings). No multi-step share form. - **Skip is always available.** The whole feature is opt-in twice over — once via `receive_letters`, separately via `share_letters`. Defaults are both OFF. diff --git a/e2e/circulation.spec.ts b/e2e/circulation.spec.ts index 80528e6..e013b40 100644 --- a/e2e/circulation.spec.ts +++ b/e2e/circulation.spec.ts @@ -1,5 +1,5 @@ import { test, expect, type Page } from '@playwright/test'; -import { setFrenchLanguage } from './helpers/mocks'; +import { injectMockSession, mockAuthRoutes, setFrenchLanguage } from './helpers/mocks'; // Inline mocks so the circulation hooks don't crash against an unmocked // Supabase URL on mount. Returning empty arrays / null is enough for the @@ -23,6 +23,8 @@ async function mockCirculationData(page: Page) { test.describe('Circulation of Love — navigation', () => { test.beforeEach(async ({ page }) => { + await injectMockSession(page); + await mockAuthRoutes(page); await setFrenchLanguage(page); await mockCirculationData(page); await page.goto('/'); diff --git a/src/hooks/useLoveLetters.ts b/src/hooks/useLoveLetters.ts index 13fbab3..1db0e6b 100644 --- a/src/hooks/useLoveLetters.ts +++ b/src/hooks/useLoveLetters.ts @@ -53,11 +53,12 @@ export function useLoveLetters(): UseLoveLetters { const refresh = useCallback(async () => { setLoading(true); setError(null); - // RLS already enforces language + opt-in + passed + live. We add the - // archived filter as a belt-and-suspenders client safeguard. + // RLS enforces opt-in + passed + live. We filter by language and archived + // here as client-side guards (defense-in-depth). const { data, error: selectError } = await supabase .from('love_letters') .select('*') + .eq('language', primaryLang) .eq('archived', false) .order('posted_at', { ascending: false }) .limit(50); @@ -68,7 +69,7 @@ export function useLoveLetters(): UseLoveLetters { } setCurrent((data ?? []) as LoveLetter[]); setLoading(false); - }, []); + }, [primaryLang]); useEffect(() => { refresh();