69 lines
2.4 KiB
JavaScript
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([]);
|
|
});
|
|
});
|