Files
vyndr/tests/unit/archetypeBadge.test.js
T
builtbykev 8bc79f3c38 Session 42: Player Intelligence System — archetypes, stat strips, player profile, enhanced cards (2011 tests)
Built from the Claude Design "VYNDR Player Intelligence" bundle (10 sections).

- Archetypes: src/services/archetypeService.js — 41 archetypes (15 NBA / 5
  WNBA-unique / 15 MLB / 6 soccer), classify -> primary+secondary+blend.
  Frontend visual map web/src/lib/archetypes.js (colors verified == backend).
  ArchetypeBadge (full/ghost/tint + glyphs) + ArchetypeBlend (DNA bar).
- StatStrip (compact/expanded): player name once, horizontal mono stats,
  inline GradeBadge props, onPlayerClick -> profile.
- Stats API: extended src/routes/stats.js with /player/:name, /leaders,
  /game/:id (rate-limited). Aggregation in playerIntelService.js (sanitizes
  name param; grades cache; graceful on cold cache). Next proxies added.
- Player Profile /player/[name]: all 9 design sections, graceful empty states.
- Enhanced GameCard (MLB pitchers + player-grouped StatStrips) + GradeResultCard
  (archetype strip + stat context + VYNDR intelligence, optional/self-hiding via
  gradeAdapter.buildIntelFields). Player-name links wired everywhere.
- Settings page replaces the S41 redirect (account/subscription/notifications/
  display/responsible-play/danger-zone with DELETE-gated delete). LINKS to the
  real /settings/security MFA page — does not replace it. + BookChip.
- Bonus: Stats Explorer /explore (real /api/stats/leaders leaderboard); added
  Explore + Settings to Nav MORE.

Deferred (need data pipelines, Session 43): Team Hub, Offseason Intel, Slate
redesign, Stats Explorer sub-panels.

Backend 1940 -> 2011 tests (+71), 157 suites. Web build clean (exit 0).

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

76 lines
2.7 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.
// Session 42 — ArchetypeBadge + ArchetypeBlend (frontend). Logic runs via the
// CommonJS lib; the .tsx is asserted as text (Phase-DH pattern).
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 arch = require('../../web/src/lib/archetypes');
const svc = require('../../src/services/archetypeService');
describe('archetypes lib — badge styling', () => {
it('full variant fills with the archetype color + white text', () => {
const s = arch.badgeStyle('POWER PULL', 'full', 'md');
expect(s.bg).toBe('#FF5C5C');
expect(s.textColor).toBe('#FFFFFF');
expect(s.borderColor).toBe('#FF5C5C');
});
it('ghost variant is transparent with a colored border', () => {
const s = arch.badgeStyle('FLOOR GENERAL', 'ghost', 'sm');
expect(s.bg).toBe('transparent');
expect(s.textColor).toBe('#4A9EFF');
expect(s.borderColor).toBe('#4A9EFFCC');
});
it('tint variant (default) uses a low-alpha tinted background', () => {
const s = arch.badgeStyle('ACE');
expect(s.bg).toBe('#A78BFA1F');
expect(s.borderColor).toBe('#A78BFA52');
});
it('archetypeColor matches and is case-insensitive', () => {
expect(arch.archetypeColor('ace')).toBe('#A78BFA');
expect(arch.archetypeColor('Two-Way Anchor')).toBe('#A78BFA');
});
it('glyphSvg returns a 16x16 svg wrapper', () => {
const svg = arch.glyphSvg('star');
expect(svg).toContain('viewBox="0 0 16 16"');
expect(svg).toContain('<path');
});
it('unknown archetype degrades to a neutral grey', () => {
expect(arch.archetypeColor('NOT REAL')).toBe('#9499A8');
});
});
describe('archetypes lib — colors agree with the backend service', () => {
it('every backend archetype color equals the frontend map color', () => {
for (const [name, a] of Object.entries(svc.ARCHETYPES)) {
expect(arch.archetypeColor(name)).toBe(a.color);
}
});
});
describe('ArchetypeBadge.tsx', () => {
const src = read('components/vyndr/ArchetypeBadge.tsx');
it('renders the glyph via dangerouslySetInnerHTML and uses mono', () => {
expect(src).toContain('dangerouslySetInnerHTML');
expect(src).toContain('badgeStyle');
expect(src).toContain('className="mono"');
});
it('supports full / ghost / tint variants', () => {
expect(src).toContain("'full' | 'ghost' | 'tint'");
});
});
describe('ArchetypeBlend.tsx', () => {
const src = read('components/vyndr/ArchetypeBlend.tsx');
it('colors segments via archetypeColor and renders a PRIMARY legend', () => {
expect(src).toContain('archetypeColor');
expect(src).toContain('PRIMARY');
expect(src).toContain('ArchetypeBadge');
});
});