ROIBot / test /alerts.test.js
Codex
Add user-gated bulk delete command
24acc72
import test from 'node:test';
import assert from 'node:assert/strict';
import { commands } from '../src/commands.js';
import {
buildAlertsButtonRows,
buildAlertsEmbed,
buildCommandsEmbed,
buildAlertRoleButtonId,
buildMarketHealthEmbed,
buildReverseAlertEmbed,
parseAlertRoleButtonId,
} from '../src/embeds.js';
test('registers the alerts slash command', () => {
const alertsCommand = commands.find((command) => command.name === 'alerts');
assert.ok(alertsCommand);
assert.match(alertsCommand.description, /alert-role embed/i);
});
test('registers the bulk delete slash command', () => {
const bulkDeleteCommand = commands.find((command) => command.name === 'bulkdeletemessages');
assert.ok(bulkDeleteCommand);
assert.match(bulkDeleteCommand.description, /bulk delete recent messages/i);
});
test('lists alerts in the public commands embed', () => {
const embed = buildCommandsEmbed().toJSON();
const alertsField = embed.fields.find((field) => field.name === '/alerts');
const sharpCommandsField = embed.fields.find((field) => field.name === 'Sharp Market Commands');
const otherOddsField = embed.fields.find((field) => field.name === 'Other Odds Commands');
assert.ok(alertsField);
assert.match(alertsField.value, /jew_olympics/i);
assert.ok(sharpCommandsField);
assert.match(sharpCommandsField.value, /dfsedgeboard/i);
assert.match(sharpCommandsField.value, /exchangeedgeboard/i);
assert.ok(otherOddsField);
assert.match(otherOddsField.value, /dfsodds/i);
assert.match(otherOddsField.value, /exchangeodds/i);
});
test('market health embed uses lane-appropriate reference language', () => {
const embed = buildMarketHealthEmbed('Market Health', [{
marketLabel: 'Hits',
lane: 'dfs',
rows: 4,
averageBooksCompared: 3.5,
averageWidthPct: 0.041,
consensusRows: 4,
}], { lane: 'dfs' }).toJSON();
assert.match(embed.fields[0].value, /DFS consensus baseline/i);
assert.doesNotMatch(embed.fields[0].value, /MGM fallback/i);
});
test('sportsbook market health embed shows fanDuel before MGM fallback', () => {
const embed = buildMarketHealthEmbed('Market Health', [{
marketLabel: 'Home Runs',
lane: 'sportsbook',
rows: 4,
averageBooksCompared: 4,
averageWidthPct: 0.05,
circaRows: 2,
fanduelFallbackRows: 1,
mgmFallbackRows: 1,
}], { lane: 'sportsbook' }).toJSON();
assert.match(embed.fields[0].value, /FanDuel fallback 1/i);
assert.match(embed.fields[0].value, /MGM fallback 1/i);
});
test('builds the alerts embed with all analyst lines', () => {
const embed = buildAlertsEmbed().toJSON();
assert.match(embed.description, /We are moving from @ everyone alerts/i);
assert.match(embed.description, /@PhazzAlerts - MLB \/ NBA/);
assert.match(embed.description, /@JRAlerts - NBA \/ MLB/);
});
test('builds two rows of alert role buttons and round-trips custom ids', () => {
const rows = buildAlertsButtonRows();
assert.equal(rows.length, 2);
assert.equal(rows[0].components.length, 3);
assert.equal(rows[1].components.length, 3);
const customId = buildAlertRoleButtonId('RIIPAlerts');
assert.equal(parseAlertRoleButtonId(customId), 'RIIPAlerts');
});
test('builds reverse alerts with explicit selection and signed odds', () => {
const embed = buildReverseAlertEmbed(
{
playerName: 'Shane Smith',
marketLabel: 'Pitcher Strikeouts',
side: 'over',
lineValue: 5.5,
sharpBook: 'BetMGM',
sharpOddsInput: '100',
},
{
book: 'DraftKings',
impliedDeltaPct: 0.0327,
previousEntry: {
side: 'over',
lineValue: 5.5,
oddsInput: '114',
},
currentEntry: {
side: 'over',
lineValue: 5.5,
oddsInput: '100',
},
},
).toJSON();
assert.equal(embed.fields[0].name, 'Selection');
assert.equal(embed.fields[0].value, 'Over 5.5');
assert.match(embed.fields[1].value, /BetMGM @ \+100/);
assert.match(embed.fields[2].value, /DraftKings Over 5\.5 \+114 -> \+100/);
});