Files
vyndr/tests/unit/vyndrCoreScreens.test.js
T
2026-07-11 14:31:53 -04:00

166 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// VYNDR 2.0 — Phase D core screens (Session 35). Adapter LOGIC is exercised
// directly via the CommonJS gradeAdapter; the .tsx screens/components are
// asserted against source text (the plain-JS Jest config has no TS transform).
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');
const adapter = require('../../web/src/lib/gradeAdapter');
describe('Phase D — grade adapter (engine → §7 contract)', () => {
const base = {
player: 'Nikola Jokic', sport: 'NBA', stat: 'home_runs', line: 26.5, direction: 'over',
grade: 'A', projection: 29.4, confidence: 67, sample_size: 34,
factors: { matchup: 'soft interior', trend: 'hot', usage: 'up', rest: 'rested', pace: 'fast' },
kill_conditions: [{ code: 'BLOWOUT', reason: 'Blowout risk caps minutes' }],
alt_lines: [{ line: 24.5, grade: 'A+' }, { line: 28.5, grade: 'B' }],
};
it('maps direction → side and humanizes the stat', () => {
const out = adapter.mapScanToGradeResult({ ...base, tier: 'desk' });
expect(out.side).toBe('Over');
expect(out.stat).toBe('Home Runs');
expect(out.player).toBe('Nikola Jokic');
});
it('computes a signed percentage edge from projection vs line', () => {
expect(adapter.computeEdge(29.4, 26.5, 'over')).toBeCloseTo(10.9, 1);
expect(adapter.computeEdge(24, 26.5, 'over')).toBeLessThan(0);
expect(adapter.computeEdge(24, 26.5, 'under')).toBeGreaterThan(0);
});
it('flags phosphor confirmed only for A/A+ with strong support', () => {
expect(adapter.isPhosphorConfirmed('A+', 80, 40)).toBe(true);
expect(adapter.isPhosphorConfirmed('A', 50, 35)).toBe(true); // sample carries it
expect(adapter.isPhosphorConfirmed('B', 90, 90)).toBe(false);
expect(adapter.isPhosphorConfirmed('A', 40, 5)).toBe(false);
});
it('FREE tier teases 3 signals, hides kill conditions and the alt ladder', () => {
const out = adapter.mapScanToGradeResult({ ...base, tier: 'free' });
expect(out.signals.length).toBe(3);
// Session 62 (A1-S1) — free gets the pricing-promised LOCKED PREVIEW
// (code-only teaser), not silence.
expect(out.killConditions.every((k) => k.includes('upgrade to see details'))).toBe(true);
expect(out.altLadder).toEqual([]);
});
it('ANALYST tier shows kill conditions + all signals, but no alt ladder', () => {
const out = adapter.mapScanToGradeResult({ ...base, tier: 'analyst' });
expect(out.signals.length).toBe(5);
expect(out.killConditions).toEqual(['Blowout risk caps minutes']);
expect(out.altLadder).toEqual([]);
});
it('DESK tier unlocks the alt line ladder', () => {
const out = adapter.mapScanToGradeResult({ ...base, tier: 'desk' });
expect(out.altLadder).toEqual([{ line: 24.5, grade: 'A+' }, { line: 28.5, grade: 'B' }]);
});
it('defaults missing fields safely', () => {
const out = adapter.mapScanToGradeResult({});
expect(out.grade).toBe('—');
expect(out.side).toBe('Over');
expect(out.signals).toEqual([]);
expect(out.books).toEqual([]);
});
});
describe('Phase D — GradeResultCard (the core moment)', () => {
const src = read('components/vyndr/GradeResultCard.tsx');
it('renders the grade letter at hero size (92116px)', () => {
expect(src).toContain('116');
expect(src).toContain('92');
});
it('uses the intel-surface for the grade hero zone + grade-reveal', () => {
expect(src).toContain('intel-surface');
expect(src).toContain('grade-reveal');
});
it('highlights the best book with green tint + green left border', () => {
expect(src).toContain('rgba(0,212,160,.13)');
expect(src).toContain("borderLeft: b.best ? '2px solid var(--g-a)'");
});
it('renders kill conditions with amber border, gated on non-empty', () => {
expect(src).toContain('hasKill');
expect(src).toContain('rgba(255,179,71,.4)');
expect(src).toContain('KILL CONDITIONS');
});
it('self-hides books / alt ladder when empty', () => {
expect(src).toContain('hasBooks');
expect(src).toContain('hasAlt');
});
});
describe('Phase D — ProcessingGrade', () => {
const src = read('components/vyndr/ProcessingGrade.tsx');
it('plays the factor-ignite + proc-scan sequence then reveals the card', () => {
expect(src).toContain('factor-ignite');
expect(src).toContain('proc-scan');
expect(src).toContain('<GradeResultCard');
});
});
describe('Phase D — GameCard (Bloomberg best/worst lines)', () => {
const src = read('components/vyndr/GameCard.tsx');
it('renders team abbreviations', () => {
expect(src).toContain('g.away.abbr');
expect(src).toContain('g.home.abbr');
});
it('best line = green tint + green border; worst = subtle red', () => {
expect(src).toContain('rgba(0,212,160,.13)');
expect(src).toContain('rgba(255,82,82,.07)');
});
it('shows a live-dot for live games and grades props with GradeBadge', () => {
expect(src).toContain('live-dot');
expect(src).toContain('<GradeBadge');
});
});
describe('Phase D — ClaimMeter', () => {
const src = read('components/vyndr/ClaimMeter.tsx');
it('renders the amber founder-seat scarcity bar', () => {
expect(src).toContain('CLAIMED');
expect(src).toContain('var(--amber)');
});
});
// Session 57 (Phase 0) — the Terminal surface was fabricated sample data
// (Finals-era NBA content rendered as live intelligence). The route now
// redirects to /dashboard; the layouts survive UNROUTED as §12 templates.
describe('Phase 0 — Terminal retired (fabricated surface)', () => {
it('the route redirects to the slate instead of rendering fake intel', () => {
const src = read('app/terminal/page.tsx');
expect(src).toContain("redirect('/dashboard')");
expect(src).not.toContain('INJURY_WIRE');
expect(src).not.toContain('Wembanyama');
});
it('preserves the VVI / cascade / leaders layouts as unrouted templates', () => {
const tpl = read('components/intel/TerminalTemplates.tsx');
expect(tpl).toContain('NOT ROUTED');
expect(tpl).toContain('VOLATILITY INDEX');
expect(tpl).toContain('INJURY WIRE');
expect(tpl).toContain('GRADEABLE LEADERS');
});
});
describe('Phase D — scan + landing wiring', () => {
it('scan renders the new ProcessingGrade card via the adapter (legacy GradeCard removed)', () => {
const src = read('app/scan/page.tsx');
expect(src).toContain('ProcessingGrade');
expect(src).toContain('mapScanToGradeResult');
expect(src).not.toContain("from '@/components/GradeCard'");
});
it('scan keeps sportsbook deep-links safe (A1 S3: BOOK_LINK_REL = sponsored noopener noreferrer)', () => {
const src = read('app/scan/page.tsx');
expect(src).toContain('rel={BOOK_LINK_REL}');
// the constant itself carries noopener noreferrer (+ sponsored)
const { BOOK_LINK_REL } = require('../../web/src/lib/bookLinks');
expect(BOOK_LINK_REL).toContain('noopener noreferrer');
});
it('landing mounts the ClaimMeter', () => {
expect(read('app/page.tsx')).toContain('ClaimMeter');
});
});