/** * DS1 (DESIGN-SPEC §4 + §17) — source invariants for the Speed + Trust bugs. * - React #418 hydration: no client-only value rendered in the SSR path * without a mounted guard. * - Loading walls: every named loader is a skeleton, not a text wall. * - Persistence: the scan write uses the authoritative session token. */ const fs = require('fs'); const path = require('path'); const WEB = path.join(__dirname, '..', '..', 'web', 'src'); const read = (rel) => fs.readFileSync(path.join(WEB, rel), 'utf8'); describe('DS1 — React #418 hydration safety (§4, audit #5)', () => { const landing = read('app/page.tsx'); test('landing no longer reads localStorage inside a useState initializer', () => { // The exact antipattern that caused #418: the client-only stored-session // check ran during render, so server (false) and client (true) diverged. expect(landing).not.toMatch(/useState\(\s*\(\)\s*=>\s*hasStoredSession\(\)\s*\)/); expect(landing).not.toMatch(/useState\(\s*\(\)\s*=>\s*hasStoredSession/); }); test('the client-only value is deferred behind a mounted flag', () => { // Server + first client render both compute maybeSignedIn from mounted=false. expect(landing).toMatch(/const\s+\[mounted,\s*setMounted\]\s*=\s*useState\(false\)/); expect(landing).toMatch(/setMounted\(true\)/); expect(landing).toMatch(/maybeSignedIn\s*=\s*mounted\s*&&\s*hasStoredSession\(\)/); }); test('hasStoredSession still guards against server-side window access', () => { expect(landing).toMatch(/typeof window === 'undefined'/); }); }); describe('DS1 — loading walls are skeletons, never text (§4, audit #5)', () => { const files = { 'dashboard slate load': 'app/dashboard/page.tsx', '/desk assembling': 'app/desk/page.tsx', '/ledger loading': 'app/ledger/page.tsx', 'scan loading': 'app/scan/page.tsx', 'landing redirect': 'app/page.tsx', }; const BANNED = [ 'Loading the slate', 'Assembling the pack', 'Loading the model', /]*>\s*Loading…\s*<\/p>/, // the bare ledger text loader ]; for (const [name, rel] of Object.entries(files)) { test(`${name} contains no text-wall loader`, () => { const src = read(rel); for (const b of BANNED) { if (typeof b === 'string') expect(src).not.toContain(b); else expect(src).not.toMatch(b); } }); } test('each loader path renders the shared Skeleton', () => { for (const rel of ['app/dashboard/page.tsx', 'app/desk/page.tsx', 'app/ledger/page.tsx', 'app/scan/page.tsx', 'app/page.tsx']) { const src = read(rel); expect(src).toMatch(/Skeleton/); expect(src).toMatch(/from '@\/components\/vyndr'/); } }); test('the Skeleton primitive is tokenized (no raw hex) and reduced-motion-safe', () => { const skel = read('components/vyndr/Skeleton.tsx'); // Uses the CSS class, no inline colors. expect(skel).toMatch(/vyndr-skeleton/); expect(skel).not.toMatch(/#[0-9a-fA-F]{3,8}/); const css = fs.readFileSync(path.join(WEB, 'app', 'globals.css'), 'utf8'); expect(css).toMatch(/\.vyndr-skeleton\s*\{/); expect(css).toMatch(/var\(--bg-surface\)/); // The global prefers-reduced-motion rule freezes every animation. expect(css).toMatch(/@media \(prefers-reduced-motion: reduce\)/); }); }); describe('DS1 — scan→ledger persistence uses the authoritative token (§17)', () => { const scan = read('app/scan/page.tsx'); test('scan pulls the bearer token from the live Supabase session', () => { expect(scan).toMatch(/session,/); // destructured from useAuth expect(scan).toMatch(/session\?\.access_token/); }); test('scan no longer relies solely on the OAuth-only legacy localStorage key', () => { // The stale key may remain only as a FALLBACK after the session token. const m = scan.match(/session\?\.access_token\s*\|\|[\s\S]{0,120}sb-token/); expect(m).toBeTruthy(); }); });