Fix Discord double-ping when autodraft fires after manual pick #47
4 changed files with 58 additions and 39 deletions
|
|
@ -853,6 +853,7 @@ export async function executeAutoPick(params: {
|
|||
participantName: participantToPick.name,
|
||||
sportName: participantToPick.sportsSeason.sport.name,
|
||||
pickNumber,
|
||||
nextPickNumber,
|
||||
round: currentRound,
|
||||
rawPickInRound,
|
||||
isDraftComplete,
|
||||
|
|
|
|||
|
|
@ -338,6 +338,7 @@ export async function action(args: ActionFunctionArgs) {
|
|||
participantName: participant.name,
|
||||
sportName: participant.sportsSeason.sport.name,
|
||||
pickNumber: currentPickNumber,
|
||||
nextPickNumber,
|
||||
round: currentRound,
|
||||
rawPickInRound,
|
||||
isDraftComplete,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const BASE_PARAMS = {
|
|||
participantName: "Erling Haaland",
|
||||
sportName: "Soccer",
|
||||
pickNumber: 1,
|
||||
nextPickNumber: 2,
|
||||
round: 1,
|
||||
rawPickInRound: 1,
|
||||
isDraftComplete: false,
|
||||
|
|
@ -56,10 +57,6 @@ function makeLeague(overrides: object = {}) {
|
|||
};
|
||||
}
|
||||
|
||||
function makeSeason(currentPickNumber = 2) {
|
||||
return { id: SEASON_ID, leagueId: LEAGUE_ID, currentPickNumber };
|
||||
}
|
||||
|
||||
function makeTeam(id: string, ownerId: string | null = null, name = "Beta United") {
|
||||
return { id, name, ownerId };
|
||||
}
|
||||
|
|
@ -70,19 +67,16 @@ function makeOwner(id: string, discordPingEnabled = true) {
|
|||
|
||||
function makeMockDb(overrides: {
|
||||
league?: object | null;
|
||||
season?: object | null;
|
||||
nextTeam?: object | null;
|
||||
owner?: object | null;
|
||||
} = {}) {
|
||||
const league = "league" in overrides ? overrides.league : makeLeague();
|
||||
const season = "season" in overrides ? overrides.season : makeSeason();
|
||||
const nextTeam = "nextTeam" in overrides ? overrides.nextTeam : makeTeam(NEXT_TEAM_ID, NEXT_OWNER_ID);
|
||||
const owner = "owner" in overrides ? overrides.owner : makeOwner(NEXT_OWNER_ID);
|
||||
|
||||
return {
|
||||
query: {
|
||||
leagues: { findFirst: vi.fn().mockResolvedValue(league) },
|
||||
seasons: { findFirst: vi.fn().mockResolvedValue(season) },
|
||||
teams: { findFirst: vi.fn().mockResolvedValue(nextTeam) },
|
||||
users: { findFirst: vi.fn().mockResolvedValue(owner) },
|
||||
},
|
||||
|
|
@ -159,24 +153,52 @@ describe("notifyPickMadeOnDiscord", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("passes nextTeamName when fresh season resolves the next slot", async () => {
|
||||
const db = makeMockDb({ season: makeSeason(2) }); // currentPickNumber=2 → pickInRound=2 → NEXT_TEAM_ID
|
||||
it("passes nextTeamName based on caller-supplied nextPickNumber", async () => {
|
||||
// pick 3 in a 2-team snake: round 2 (reversed) → draftOrder 2 → NEXT_TEAM_ID → "Beta United"
|
||||
const db = makeMockDb();
|
||||
|
||||
await notifyPickMadeOnDiscord({ ...BASE_PARAMS, db: db as never });
|
||||
await notifyPickMadeOnDiscord({ ...BASE_PARAMS, nextPickNumber: 3, db: db as never });
|
||||
|
||||
expect(sendPickAnnouncementNotification).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ nextTeamName: "Beta United" })
|
||||
);
|
||||
});
|
||||
|
||||
it("reads next team from fresh DB pick number, not caller-supplied snapshot", async () => {
|
||||
// Simulate autodraft chain advancing 2 picks: currentPickNumber=3 on a 2-team snake
|
||||
// draft means pickInRound=2 again (round 2 reversed) → NEXT_TEAM_ID
|
||||
const db = makeMockDb({ season: makeSeason(3) });
|
||||
it("uses caller-supplied nextPickNumber instead of reading from DB", async () => {
|
||||
const db = makeMockDb();
|
||||
|
||||
await notifyPickMadeOnDiscord({ ...BASE_PARAMS, db: db as never });
|
||||
|
||||
expect(db.query.seasons.findFirst).toHaveBeenCalledTimes(1);
|
||||
expect((db.query as Record<string, unknown>).seasons).toBeUndefined();
|
||||
});
|
||||
|
||||
it("shows the immediate next drafter, not the post-autodraft-chain drafter", async () => {
|
||||
// Regression: manual pick #1 by alpha; beta immediately autodrafts (#2); DB advances to pick #3.
|
||||
// Discord for pick #1 must show beta ("On the clock: beta"), not gamma.
|
||||
// Uses a 3-team snake: pick 1→alpha, pick 2→beta, pick 3→gamma.
|
||||
const ALPHA_ID = "team-alpha";
|
||||
const BETA_ID = "team-beta";
|
||||
const GAMMA_ID = "team-gamma";
|
||||
const threeTeamSlots = [
|
||||
{ teamId: ALPHA_ID, draftOrder: 1 },
|
||||
{ teamId: BETA_ID, draftOrder: 2 },
|
||||
{ teamId: GAMMA_ID, draftOrder: 3 },
|
||||
];
|
||||
const betaTeam = { id: BETA_ID, name: "Beta Squad", ownerId: null };
|
||||
const db = makeMockDb({ nextTeam: betaTeam });
|
||||
|
||||
await notifyPickMadeOnDiscord({
|
||||
...BASE_PARAMS,
|
||||
pickNumber: 1,
|
||||
nextPickNumber: 2, // immediately after alpha's pick — before beta's autodraft
|
||||
totalTeams: 3,
|
||||
draftSlots: threeTeamSlots,
|
||||
db: db as never,
|
||||
});
|
||||
|
||||
expect(sendPickAnnouncementNotification).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ nextTeamName: "Beta Squad" })
|
||||
);
|
||||
});
|
||||
|
||||
it("passes nextOwnerDiscordId when owner has discordPingEnabled", async () => {
|
||||
|
|
@ -216,7 +238,7 @@ describe("notifyPickMadeOnDiscord", () => {
|
|||
|
||||
await notifyPickMadeOnDiscord({ ...BASE_PARAMS, isDraftComplete: true, db: db as never });
|
||||
|
||||
expect(db.query.seasons.findFirst).not.toHaveBeenCalled();
|
||||
expect(db.query.teams.findFirst).not.toHaveBeenCalled();
|
||||
expect(sendPickAnnouncementNotification).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ isDraftComplete: true, nextTeamName: undefined })
|
||||
);
|
||||
|
|
@ -235,7 +257,7 @@ describe("notifyPickMadeOnDiscord", () => {
|
|||
it("uses sequential (not snake-adjusted) pick number in Discord title for even rounds", async () => {
|
||||
// 13-team draft, pick #22: round 2 (even/reversed), rawPickInRound=9, snake-adjusted slot=5
|
||||
// Discord should say "Round 2, Pick 9" not "Round 2, Pick 5"
|
||||
const db = makeMockDb({ season: makeSeason(23) });
|
||||
const db = makeMockDb();
|
||||
|
||||
await notifyPickMadeOnDiscord({
|
||||
...BASE_PARAMS,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export async function notifyPickMadeOnDiscord(params: {
|
|||
participantName: string;
|
||||
sportName: string;
|
||||
pickNumber: number;
|
||||
nextPickNumber: number;
|
||||
round: number;
|
||||
rawPickInRound: number;
|
||||
isDraftComplete: boolean;
|
||||
|
|
@ -37,6 +38,7 @@ export async function notifyPickMadeOnDiscord(params: {
|
|||
participantName,
|
||||
sportName,
|
||||
pickNumber,
|
||||
nextPickNumber,
|
||||
round,
|
||||
rawPickInRound,
|
||||
isDraftComplete,
|
||||
|
|
@ -57,28 +59,21 @@ export async function notifyPickMadeOnDiscord(params: {
|
|||
let nextOwnerDiscordId: string | undefined;
|
||||
|
||||
if (!isDraftComplete) {
|
||||
// Read currentPickNumber fresh from DB so we see the post-autodraft-chain state,
|
||||
// matching the same guarantee sendOnTheClockEmail provides.
|
||||
const freshSeason = await db.query.seasons.findFirst({
|
||||
where: eq(schema.seasons.id, seasonId),
|
||||
});
|
||||
if (freshSeason) {
|
||||
const nextPickInRound = pickInRoundFor(freshSeason.currentPickNumber ?? 1, totalTeams);
|
||||
const nextSlot = draftSlots.find((s) => s.draftOrder === nextPickInRound);
|
||||
if (nextSlot) {
|
||||
const nextTeam = await db.query.teams.findFirst({
|
||||
where: eq(schema.teams.id, nextSlot.teamId),
|
||||
});
|
||||
if (nextTeam) {
|
||||
nextTeamName = nextTeam.name;
|
||||
if (nextTeam.ownerId) {
|
||||
const owner = await db.query.users.findFirst({
|
||||
where: eq(schema.users.id, nextTeam.ownerId),
|
||||
});
|
||||
if (owner?.discordPingEnabled) {
|
||||
const discordIds = await findDiscordIdsByUserIds([owner.id]);
|
||||
nextOwnerDiscordId = discordIds.get(owner.id);
|
||||
}
|
||||
const nextPickInRound = pickInRoundFor(nextPickNumber, totalTeams);
|
||||
const nextSlot = draftSlots.find((s) => s.draftOrder === nextPickInRound);
|
||||
if (nextSlot) {
|
||||
const nextTeam = await db.query.teams.findFirst({
|
||||
where: eq(schema.teams.id, nextSlot.teamId),
|
||||
});
|
||||
if (nextTeam) {
|
||||
nextTeamName = nextTeam.name;
|
||||
if (nextTeam.ownerId) {
|
||||
const owner = await db.query.users.findFirst({
|
||||
where: eq(schema.users.id, nextTeam.ownerId),
|
||||
});
|
||||
if (owner?.discordPingEnabled) {
|
||||
const discordIds = await findDiscordIdsByUserIds([owner.id]);
|
||||
nextOwnerDiscordId = discordIds.get(owner.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue