Files
vyndr/tests/unit/bookComparisonService.test.js
T

69 lines
2.4 KiB
JavaScript

// Unit: book comparison service (Session 28). Pure functions.
const { compareProp, bestLines } = require('../../src/services/bookComparisonService');
const prop = {
player: 'Wembanyama',
stat_type: 'points',
lines: [
{ book: 'draftkings', line: 28.5, over_odds: -110, under_odds: -110 },
{ book: 'fanduel', line: 28.5, over_odds: -105, under_odds: -115 }, // best over
{ book: 'betmgm', line: 28.5, over_odds: -120, under_odds: -102 }, // best under
],
};
describe('bookComparisonService — compareProp', () => {
test('identifies the best OVER line (highest payout)', () => {
const c = compareProp(prop, 'over');
expect(c.bestBook).toBe('fanduel'); // -105 pays more than -110/-120
expect(c.bestOdds).toBe(-105);
expect(c.books.find((b) => b.book === 'fanduel').isBest).toBe(true);
expect(c.bookCount).toBe(3);
});
test('identifies the best UNDER line', () => {
const c = compareProp(prop, 'under');
expect(c.bestBook).toBe('betmgm'); // -102 pays more than -110/-115
expect(c.bestOdds).toBe(-102);
});
test('savings is positive (best beats the field average)', () => {
const c = compareProp(prop, 'over');
expect(c.savings).toBeGreaterThan(0);
});
test('single-book prop still compares (bookCount 1)', () => {
const c = compareProp({ player: 'X', stat_type: 'hits', lines: [{ book: 'dk', over_odds: -110 }] }, 'over');
expect(c.bookCount).toBe(1);
expect(c.bestBook).toBe('dk');
});
test('no usable lines → null, not crash', () => {
expect(compareProp({ player: 'X', stat_type: 'hits', lines: [] }, 'over')).toBeNull();
expect(compareProp({ player: 'X', stat_type: 'hits' }, 'over')).toBeNull();
});
});
describe('bookComparisonService — bestLines', () => {
test('drops single-book props and sorts by savings desc', () => {
const props = [
prop,
{ player: 'Solo', stat_type: 'reb', lines: [{ book: 'dk', over_odds: -110 }] }, // 1 book → dropped
{
player: 'BigEdge', stat_type: 'ast',
lines: [
{ book: 'dk', over_odds: -200 },
{ book: 'fd', over_odds: +120 }, // huge spread → big savings
],
},
];
const lines = bestLines(props, { side: 'over' });
expect(lines.map((l) => l.player)).not.toContain('Solo');
expect(lines[0].player).toBe('BigEdge'); // biggest savings first
});
test('non-array input → empty', () => {
expect(bestLines(null)).toEqual([]);
});
});