scorecard-fence.test.ts2.0 KBView on GitHub import { parseScorecard, toneForScore, parseScore } from '@/modules/documents/coaching/scorecard-fence';
const T=['| Discovery | Score | Team | Why |','| --- | --- | --- | --- |','| D1 Knew the must-asks | 4 | 3.6 | Got detail count. |','| D2 Genuinely curious | 2 | 3.4 | 4 pains dropped. |','| D3 Reason to act now | na | 3.5 | No chance. |'].join('\n');
describe('scorecard fence', () => {
it('parses title, series and rows', () => {
const p = parseScorecard(T)!;
expect(p.title).toBe('Discovery');
expect(p.seriesKeys).toEqual(['Team']);
expect(p.reasonLabel).toBe('Why');
expect(p.rows).toHaveLength(3);
expect(p.rows[0].score).toBe(4);
expect(p.rows[0].extra.Team).toBe(3.6);
expect(p.rows[2].score).toBeNull();
expect(p.average).toBe(3);
});
it('bands at the boundaries Peter specified', () => {
expect(toneForScore(2.9)).toBe('red');
expect(toneForScore(3)).toBe('amber');
expect(toneForScore(3.9)).toBe('amber');
expect(toneForScore(4)).toBe('green');
expect(toneForScore(null)).toBe('muted');
});
it('accepts 4/5 and rejects junk', () => {
expect(parseScore('4/5')).toBe(4);
expect(parseScore('n/a')).toBeNull();
expect(parseScorecard('not a table')).toBeNull();
expect(parseScorecard('| a | b |\n| c | d |')).toBeNull();
});
});
describe('decimal scores', () => {
const D = ['| Discovery | Score | Why |','| --- | --- | --- |','| D1 Knew the must-asks | 2.8 | x |','| D2 Genuinely curious | 4.2 | y |','| D3 Reason to act now | 1.0 | z |'].join('\n');
it('parses one-decimal scores and averages them to one decimal', () => {
const p = parseScorecard(D)!;
expect(p.rows.map((r) => r.score)).toEqual([2.8, 4.2, 1.0]);
expect(p.average).toBe(2.7);
});
it('bands decimals on the documented boundaries', () => {
expect(toneForScore(2.9)).toBe('red');
expect(toneForScore(3.0)).toBe('amber');
expect(toneForScore(3.99)).toBe('amber');
expect(toneForScore(4.0)).toBe('green');
});
});