Files
vyndr/tests/unit/playerIntelCards.test.js
T
builtbykev 7969a4971a Session 44: Make it visible — VYNDR archetype names, grade intel, schedule fix, landing page (2061 tests)
Frontend + wiring only. Wires existing backend into the pages users see.

- VYNDR Original archetype rename (41) across archetypeService.js + lib/
  archetypes.js + ArchetypeBadge, each keeping legacyName (resolves stale data).
  Judge -> BOMBER. Old POWER PULL slot -> WHIFF strikeout-artist pitcher.
- BACKEND_HANDOFF.md: canonical frontend<->backend data contract.
- Grade card intel: scan/page.tsx now forwards the engine's intel fields
  (season_avg/form/usage/matchup_grade/archetype/...) into mapScanToGradeResult
  -> STAT CONTEXT + VYNDR INTELLIGENCE sections populate. The chain already
  preserved them (tierGating + /api/scan spread); the page was dropping them.
- Schedule freshness: slateAdapter.isRelevantGame drops completed games >24h
  old; Slate.filteredGames applies it. (TTL already 60s.)
- Landing: Features.tsx rewritten to user-facing copy (no Point-biserial/Zone
  14/ABS/Phi-coefficient).
- Depth chart Next proxies added (/api/stats/lineup|depth|cascade) - were 404.
- GameCard swap DEFERRED (Kev): legacy on-demand card stays as a bridge until
  the snapshot pipeline populates the grades cache; vyndr/GameCard swaps in then.

Backend 2045 -> 2061 tests (+16), 167 suites. Web build clean (exit 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 20:15:38 -04:00

64 lines
2.7 KiB
JavaScript

// Session 42 — Phase 4: grade-adapter intel fields + enhanced game card.
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 { mapScanToGradeResult, buildIntelFields } = require('../../web/src/lib/gradeAdapter');
describe('gradeAdapter — Player Intelligence fields', () => {
it('omits all new sections when the engine supplies nothing (self-hide)', () => {
const r = mapScanToGradeResult({ player: 'X', stat: 'points', line: 26.5, grade: 'A' });
expect(r.archetypeBlend).toBeUndefined();
expect(r.statContext).toBeUndefined();
expect(r.vyndrIntel).toBeUndefined();
expect(r.propDNA).toBeUndefined();
});
it('lifts a single archetype name into a one-segment blend', () => {
const f = buildIntelFields({ archetype: 'TORCH' });
expect(f.archetypeBlend).toEqual([{ archetype: 'TORCH', weight: 1 }]);
});
it('passes through a full blend + propDNA + statContext + vyndrIntel', () => {
const r = mapScanToGradeResult({
player: 'Wemby', stat: 'points', line: 26.5, grade: 'A',
archetype_blend: [{ archetype: 'FORTRESS', weight: 0.6 }, { archetype: 'ARTILLERY', weight: 0.4 }],
prop_dna: { reliable: ['points'], volatile: ['rebounds'] },
season_avg: 26.9, last10_avg: 28.4, vs_opp_avg: 30.1,
form: 92, usage: '31.2%', matchup_grade: 'A', rest: '+2.4%',
});
expect(r.archetypeBlend).toHaveLength(2);
expect(r.propDNA.reliable).toContain('points');
expect(r.statContext).toEqual({ season: '26.9', last10: '28.4', vsOpp: '30.1' });
expect(r.vyndrIntel).toEqual({ form: 92, usage: '31.2%', matchup: 'A', rest: '+2.4%' });
});
});
describe('GradeResultCard — new sections', () => {
const src = read('components/vyndr/GradeResultCard.tsx');
it('renders the archetype strip + STAT CONTEXT + VYNDR INTELLIGENCE', () => {
expect(src).toContain('ARCHETYPE STRIP');
expect(src).toContain('STAT CONTEXT');
expect(src).toContain('VYNDR INTELLIGENCE');
expect(src).toContain('ArchetypeBlend');
});
});
describe('Enhanced GameCard (Session 42)', () => {
const src = read('components/vyndr/GameCard.tsx');
it('renders MLB starting pitchers when provided', () => {
expect(src).toContain('g.pitchers');
expect(src).toContain('STARTING');
expect(src).toContain('ERA');
});
it('prefers the player-grouped StatStrip (name once) over per-prop rows', () => {
expect(src).toContain('g.playerStrips');
expect(src).toContain('StatStrip');
expect(src).toContain('variant="compact"');
});
it('links player names to their profile', () => {
expect(src).toContain('playerHref');
});
});