81 lines
2.9 KiB
JavaScript
81 lines
2.9 KiB
JavaScript
jest.mock('../../src/services/intelligence/gameLogService', () => ({
|
|
getGameLogs: async () => null,
|
|
}));
|
|
|
|
const cs = require('../../src/services/intelligence/consistencyScore');
|
|
|
|
describe('consistencyScore.classify', () => {
|
|
test('cv < 0.15 → elite', () => {
|
|
expect(cs.classify(0.10)).toEqual({ consistency: 'elite', score: 1.0 });
|
|
});
|
|
test('cv 0.15-0.30 → reliable', () => {
|
|
expect(cs.classify(0.20)).toEqual({ consistency: 'reliable', score: 0.7 });
|
|
});
|
|
test('cv 0.30-0.50 → volatile', () => {
|
|
expect(cs.classify(0.40)).toEqual({ consistency: 'volatile', score: 0.4 });
|
|
});
|
|
test('cv >= 0.50 → boom_bust', () => {
|
|
expect(cs.classify(0.80)).toEqual({ consistency: 'boom_bust', score: 0.1 });
|
|
});
|
|
});
|
|
|
|
describe('consistencyScore.statsFor', () => {
|
|
test('null for fewer than 2 samples', () => {
|
|
expect(cs.statsFor([])).toBeNull();
|
|
expect(cs.statsFor([25])).toBeNull();
|
|
});
|
|
|
|
test('null when mean is zero (can\'t divide)', () => {
|
|
expect(cs.statsFor([0, 0, 0])).toBeNull();
|
|
});
|
|
|
|
test('computes mean / stddev / cv for tight values', () => {
|
|
const s = cs.statsFor([25, 24, 26, 25, 24]);
|
|
expect(s.mean).toBeCloseTo(24.8, 1);
|
|
expect(s.cv).toBeLessThan(0.05);
|
|
});
|
|
|
|
test('computes wide cv for volatile sample', () => {
|
|
const s = cs.statsFor([5, 30, 35, 8, 28, 12]);
|
|
expect(s.cv).toBeGreaterThan(0.4);
|
|
});
|
|
});
|
|
|
|
describe('consistencyScore.getConsistency', () => {
|
|
test('classifies an elite scorer', async () => {
|
|
const logs = [
|
|
{ points: 25 }, { points: 24 }, { points: 26 }, { points: 25 }, { points: 24 },
|
|
{ points: 25 }, { points: 26 }, { points: 24 }, { points: 25 }, { points: 25 },
|
|
];
|
|
const out = await cs.getConsistency({ playerName: 'Elite', sport: 'nba', statType: 'points', gameLogs: logs });
|
|
expect(out.consistency).toBe('elite');
|
|
expect(out.games).toBe(10);
|
|
});
|
|
|
|
test('classifies boom/bust', async () => {
|
|
const logs = [
|
|
{ points: 5 }, { points: 32 }, { points: 8 }, { points: 35 }, { points: 6 },
|
|
{ points: 28 }, { points: 4 }, { points: 30 }, { points: 9 }, { points: 26 },
|
|
];
|
|
const out = await cs.getConsistency({ playerName: 'Wild', sport: 'nba', statType: 'points', gameLogs: logs });
|
|
expect(out.consistency).toBe('boom_bust');
|
|
});
|
|
|
|
test('returns unknown when game logs empty', async () => {
|
|
const out = await cs.getConsistency({ playerName: 'NoData', sport: 'nba', statType: 'points', gameLogs: [] });
|
|
expect(out.consistency).toBe('unknown');
|
|
expect(out.score).toBeNull();
|
|
});
|
|
|
|
test('combo stat (pts_reb_ast) summed before measuring', async () => {
|
|
const logs = [
|
|
{ points: 20, rebounds: 5, assists: 5 },
|
|
{ points: 22, rebounds: 5, assists: 4 },
|
|
{ points: 18, rebounds: 6, assists: 5 },
|
|
{ points: 21, rebounds: 5, assists: 5 },
|
|
];
|
|
const out = await cs.getConsistency({ playerName: 'Combo', sport: 'nba', statType: 'pts_reb_ast', gameLogs: logs });
|
|
expect(out.consistency).toBe('elite');
|
|
});
|
|
});
|