Updated all model files to use the renamed schema exports from Task 1: - participants → seasonParticipants - participantExpectedValues → seasonParticipantExpectedValues - participantQualifyingTotals → seasonParticipantQualifyingTotals - participantResults → seasonParticipantResults - participantSurfaceElos → seasonParticipantSurfaceElos - eventResults.participantId → eventResults.seasonParticipantId - db.query relation accessors updated - Relation field .participant → .seasonParticipant where applicable - Import paths updated: ./participant → ./season-participant Files updated (14 model files + 3 test files): - draft-pick.ts - draft-utils.ts - event-result.ts - group-stage-match.ts - participant-result.ts - qualifying-points.ts - scoring-calculator.ts - scoring-event.ts - sports-season.ts - surface-elo.ts - team-score-events.ts - cs2-major-stage.ts - golf-skills.ts - participant-expected-value.ts - __tests__/sports-season.clone.test.ts - __tests__/auto-pick.test.ts - __tests__/executeAutoPick.timer.test.ts Typecheck errors decreased: 779 → 499 (280 fewer) All model file errors related to renamed schemas resolved. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
590 lines
20 KiB
TypeScript
590 lines
20 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||
import { autoPickForTeam, pruneIneligibleQueueItems } from "../draft-utils";
|
||
|
||
// Mock all external model dependencies so we can control their return values
|
||
vi.mock("~/models/draft-pick", () => ({
|
||
getDraftPicksWithSports: vi.fn(),
|
||
getTeamDraftPicksWithSports: vi.fn(),
|
||
isParticipantDrafted: vi.fn(),
|
||
}));
|
||
|
||
vi.mock("~/models/participant", () => ({
|
||
getParticipantsForSeasonWithSports: vi.fn(),
|
||
}));
|
||
|
||
vi.mock("~/models/season-sport", () => ({
|
||
getSeasonSportsSimple: vi.fn(),
|
||
}));
|
||
|
||
vi.mock("~/models/draft-queue", () => ({
|
||
getTeamQueue: vi.fn(),
|
||
getAllQueuesForSeason: vi.fn(),
|
||
}));
|
||
|
||
vi.mock("~/lib/draft-eligibility", () => ({
|
||
calculateDraftEligibility: vi.fn(),
|
||
}));
|
||
|
||
// Prevent actual socket/db usage
|
||
vi.mock("~/server/socket");
|
||
vi.mock("~/database/context");
|
||
|
||
import {
|
||
getDraftPicksWithSports,
|
||
getTeamDraftPicksWithSports,
|
||
isParticipantDrafted,
|
||
} from "~/models/draft-pick";
|
||
import { getParticipantsForSeasonWithSports } from "~/models/season-participant";
|
||
import { getSeasonSportsSimple } from "~/models/season-sport";
|
||
import { getTeamQueue, getAllQueuesForSeason } from "~/models/draft-queue";
|
||
import { calculateDraftEligibility } from "~/lib/draft-eligibility";
|
||
|
||
const SEASON_ID = "season-1";
|
||
const TEAM_ID = "team-1";
|
||
const DRAFT_ROUNDS = 10;
|
||
const ALL_TEAM_IDS = [TEAM_ID, "team-2"];
|
||
|
||
// A minimal mock db for cases that do NOT reach getTopAvailableParticipant.
|
||
// `where` resolves to [] so `await db.select()...where()` yields an array.
|
||
function makeMockDb(overrides: Record<string, unknown> = {}) {
|
||
const mockDb: Record<string, unknown> = {
|
||
query: {
|
||
seasonParticipants: {
|
||
findMany: vi.fn().mockResolvedValue([]),
|
||
},
|
||
},
|
||
select: vi.fn().mockReturnThis(),
|
||
from: vi.fn().mockReturnThis(),
|
||
innerJoin: vi.fn().mockReturnThis(),
|
||
where: vi.fn().mockResolvedValue([]),
|
||
orderBy: vi.fn().mockResolvedValue([]),
|
||
delete: vi.fn().mockReturnThis(),
|
||
...overrides,
|
||
};
|
||
return mockDb;
|
||
}
|
||
|
||
// Build a mock db whose select chain returns a real EV participant.
|
||
// getTopAvailableParticipant makes three sequential awaitable calls:
|
||
// 1. select().from().where() → drafted picks → []
|
||
// 2. select().from().innerJoin()×2.where() → season sports → [{sportsSeasonId, sportId}]
|
||
// 3. select().from().where().orderBy() → top participant → [{id, ...}]
|
||
function makeMockDbWithEvParticipant(participantId: string) {
|
||
return {
|
||
query: { seasonParticipants: { findMany: vi.fn().mockResolvedValue([]) } },
|
||
select: vi.fn().mockReturnThis(),
|
||
from: vi.fn().mockReturnThis(),
|
||
innerJoin: vi.fn().mockReturnThis(),
|
||
where: vi.fn()
|
||
.mockResolvedValueOnce([]) // call 1: drafted picks
|
||
.mockResolvedValueOnce([{ sportsSeasonId: "ss-1", sportId: "sport-1" }]) // call 2: season sports
|
||
.mockReturnThis(), // call 3: chain to orderBy
|
||
orderBy: vi.fn().mockResolvedValue([
|
||
{ id: participantId, name: "EV Player", expectedValue: "100.00" },
|
||
]),
|
||
delete: vi.fn().mockReturnThis(),
|
||
};
|
||
}
|
||
|
||
// Minimal eligibility stub — makes every sport eligible.
|
||
function stubEligibility() {
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue({
|
||
eligibleSportIds: new Set(["sport-1"]),
|
||
} as ReturnType<typeof calculateDraftEligibility>);
|
||
}
|
||
|
||
beforeEach(() => {
|
||
vi.clearAllMocks();
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getTeamDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([]);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
stubEligibility();
|
||
});
|
||
|
||
describe("autoPickForTeam – queueOnly constraint (AC2 & AC3)", () => {
|
||
describe("empty queue", () => {
|
||
it("returns null when queueOnly=true (no EV fallback)", async () => {
|
||
vi.mocked(getTeamQueue).mockResolvedValue([]);
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
makeMockDb() as any,
|
||
true // queueOnly
|
||
);
|
||
|
||
expect(result).toBeNull();
|
||
});
|
||
|
||
it("returns the top EV participant when queueOnly=false (falls back to EV)", async () => {
|
||
vi.mocked(getTeamQueue).mockResolvedValue([]);
|
||
|
||
const mockDb = makeMockDbWithEvParticipant("p-ev");
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
false // queueOnly off
|
||
);
|
||
|
||
// Must return the EV participant — proves the EV path ran, not the queueOnly guard.
|
||
expect(result).toBe("p-ev");
|
||
});
|
||
});
|
||
|
||
describe("all queue items already drafted", () => {
|
||
it("returns null when queueOnly=true and every queued participant is taken", async () => {
|
||
const queue = [
|
||
{ id: "q-1", participantId: "p-1", queuePosition: 1 },
|
||
{ id: "q-2", participantId: "p-2", queuePosition: 2 },
|
||
];
|
||
vi.mocked(getTeamQueue).mockResolvedValue(queue as any);
|
||
|
||
const mockDb = makeMockDb({
|
||
query: {
|
||
participants: {
|
||
findMany: vi.fn().mockResolvedValue([
|
||
{
|
||
id: "p-1",
|
||
name: "Player One",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
{
|
||
id: "p-2",
|
||
name: "Player Two",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
});
|
||
|
||
// Both participants are already drafted
|
||
vi.mocked(isParticipantDrafted).mockResolvedValue(true);
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
true // queueOnly
|
||
);
|
||
|
||
expect(result).toBeNull();
|
||
});
|
||
|
||
it("removes stale queue entries when all items are drafted", async () => {
|
||
const queue = [{ id: "q-1", participantId: "p-1", queuePosition: 1 }];
|
||
vi.mocked(getTeamQueue).mockResolvedValue(queue as any);
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockWhere = vi.fn().mockResolvedValue(undefined);
|
||
const mockDb = makeMockDb({
|
||
query: {
|
||
participants: {
|
||
findMany: vi.fn().mockResolvedValue([
|
||
{
|
||
id: "p-1",
|
||
name: "Player One",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
delete: mockDelete,
|
||
where: mockWhere,
|
||
});
|
||
|
||
vi.mocked(isParticipantDrafted).mockResolvedValue(true);
|
||
|
||
await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
true
|
||
);
|
||
|
||
// Stale items should be cleaned from the queue
|
||
expect(mockDelete).toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe("ineligible sport — only queued player's sport is full", () => {
|
||
it("removes the ineligible queue item and returns null when queueOnly=true", async () => {
|
||
// Scenario: team has a snooker player queued but snooker is already full (not in eligibleSportIds)
|
||
const queue = [{ id: "q-snooker", participantId: "p-snooker", queuePosition: 1 }];
|
||
vi.mocked(getTeamQueue).mockResolvedValue(queue as any);
|
||
|
||
// Snooker is NOT eligible — only "sport-other" is
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue({
|
||
eligibleSportIds: new Set(["sport-other"]),
|
||
} as ReturnType<typeof calculateDraftEligibility>);
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockWhere = vi.fn().mockResolvedValue(undefined);
|
||
const mockDb = makeMockDb({
|
||
query: {
|
||
participants: {
|
||
findMany: vi.fn().mockResolvedValue([
|
||
{
|
||
id: "p-snooker",
|
||
name: "Ronnie O'Sullivan",
|
||
sportsSeason: { sport: { id: "sport-snooker", name: "Snooker" } },
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
delete: mockDelete,
|
||
where: mockWhere,
|
||
});
|
||
|
||
vi.mocked(isParticipantDrafted).mockResolvedValue(false); // not drafted — ineligible due to sport
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
true // queueOnly — no EV fallback
|
||
);
|
||
|
||
// Queue item should be removed
|
||
expect(mockDelete).toHaveBeenCalled();
|
||
// No valid pick available
|
||
expect(result).toBeNull();
|
||
});
|
||
|
||
it("falls back to EV pick from eligible sports when queueOnly=false", async () => {
|
||
// Scenario: same ineligible snooker player, but queueOnly is off so system picks best available
|
||
const queue = [{ id: "q-snooker", participantId: "p-snooker", queuePosition: 1 }];
|
||
vi.mocked(getTeamQueue).mockResolvedValue(queue as any);
|
||
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue({
|
||
eligibleSportIds: new Set(["sport-other"]),
|
||
} as ReturnType<typeof calculateDraftEligibility>);
|
||
|
||
// where() call order:
|
||
// 1. delete().where() — remove ineligible snooker item from queue
|
||
// 2. select().from().where() — getTopAvailableParticipant: drafted picks → []
|
||
// 3. select().from().innerJoin().innerJoin().where() — season sports → [{...}]
|
||
// 4. select().from(participants).where().orderBy() — participant query (chain)
|
||
const mockDb = {
|
||
query: {
|
||
participants: {
|
||
findMany: vi.fn().mockResolvedValue([
|
||
{
|
||
id: "p-snooker",
|
||
name: "Ronnie O'Sullivan",
|
||
sportsSeason: { sport: { id: "sport-snooker", name: "Snooker" } },
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
select: vi.fn().mockReturnThis(),
|
||
from: vi.fn().mockReturnThis(),
|
||
innerJoin: vi.fn().mockReturnThis(),
|
||
where: vi.fn()
|
||
.mockResolvedValueOnce(undefined) // call 1: delete ineligible queue items
|
||
.mockResolvedValueOnce([]) // call 2: drafted picks
|
||
.mockResolvedValueOnce([{ sportsSeasonId: "ss-other", sportId: "sport-other" }]) // call 3: season sports
|
||
.mockReturnThis(), // call 4: participant query → chain to orderBy
|
||
orderBy: vi.fn().mockResolvedValue([
|
||
{ id: "p-ev", name: "EV Player", expectedValue: "90.00" },
|
||
]),
|
||
delete: vi.fn().mockReturnThis(),
|
||
};
|
||
|
||
vi.mocked(isParticipantDrafted).mockResolvedValue(false);
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
false // queueOnly off — should fall back to best available
|
||
);
|
||
|
||
// Should pick the best available from eligible sports, not the snooker player
|
||
expect(result).toBe("p-ev");
|
||
});
|
||
});
|
||
|
||
describe("partial queue — first item drafted, second available", () => {
|
||
it("skips drafted item and returns the next valid participant", async () => {
|
||
const queue = [
|
||
{ id: "q-1", participantId: "p-1", queuePosition: 1 },
|
||
{ id: "q-2", participantId: "p-2", queuePosition: 2 },
|
||
];
|
||
vi.mocked(getTeamQueue).mockResolvedValue(queue as any);
|
||
|
||
const mockDb = makeMockDb({
|
||
query: {
|
||
participants: {
|
||
findMany: vi.fn().mockResolvedValue([
|
||
{
|
||
id: "p-1",
|
||
name: "Player One",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
{
|
||
id: "p-2",
|
||
name: "Player Two",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
});
|
||
|
||
// p-1 is already drafted, p-2 is available
|
||
vi.mocked(isParticipantDrafted).mockImplementation(
|
||
async (_seasonId, participantId) => participantId === "p-1"
|
||
);
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
true // queueOnly — still uses queue, just no EV fallback
|
||
);
|
||
|
||
expect(result).toBe("p-2");
|
||
});
|
||
|
||
it("returns the first available participant when none are drafted (happy path)", async () => {
|
||
const queue = [
|
||
{ id: "q-1", participantId: "p-1", queuePosition: 1 },
|
||
{ id: "q-2", participantId: "p-2", queuePosition: 2 },
|
||
];
|
||
vi.mocked(getTeamQueue).mockResolvedValue(queue as any);
|
||
|
||
const mockDb = makeMockDb({
|
||
query: {
|
||
participants: {
|
||
findMany: vi.fn().mockResolvedValue([
|
||
{
|
||
id: "p-1",
|
||
name: "Player One",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
{
|
||
id: "p-2",
|
||
name: "Player Two",
|
||
sportsSeason: { sport: { id: "sport-1", name: "NFL" } },
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
});
|
||
|
||
vi.mocked(isParticipantDrafted).mockResolvedValue(false);
|
||
|
||
const result = await autoPickForTeam(
|
||
SEASON_ID,
|
||
TEAM_ID,
|
||
DRAFT_ROUNDS,
|
||
ALL_TEAM_IDS,
|
||
mockDb as any,
|
||
true
|
||
);
|
||
|
||
expect(result).toBe("p-1");
|
||
});
|
||
});
|
||
});
|
||
|
||
function makeSeasonQueues(entries: [string, { id: string; participantId: string; queuePosition: number }[]][]) {
|
||
return new Map(entries.map(([teamId, items]) => [teamId, items as any]));
|
||
}
|
||
|
||
describe("pruneIneligibleQueueItems", () => {
|
||
beforeEach(() => {
|
||
vi.clearAllMocks();
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getTeamDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([]);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
});
|
||
|
||
it("removes queued snooker player when snooker is no longer eligible for a team", async () => {
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([
|
||
{ id: "p-snooker", name: "Ronnie O'Sullivan", sport: { id: "sport-snooker", name: "Snooker" } },
|
||
] as any);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
|
||
// team-1: snooker ineligible; team-2: snooker still eligible
|
||
vi.mocked(calculateDraftEligibility)
|
||
.mockReturnValueOnce({ eligibleSportIds: new Set([]) } as any)
|
||
.mockReturnValueOnce({ eligibleSportIds: new Set(["sport-snooker"]) } as any);
|
||
|
||
vi.mocked(getAllQueuesForSeason).mockResolvedValue(
|
||
makeSeasonQueues([
|
||
[TEAM_ID, [{ id: "q-1", participantId: "p-snooker", queuePosition: 1 }]],
|
||
["team-2", []],
|
||
])
|
||
);
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockWhere = vi.fn().mockResolvedValue(undefined);
|
||
const mockDb = makeMockDb({ delete: mockDelete, where: mockWhere });
|
||
|
||
const result = await pruneIneligibleQueueItems({
|
||
seasonId: SEASON_ID,
|
||
draftRounds: DRAFT_ROUNDS,
|
||
allTeamIds: ALL_TEAM_IDS,
|
||
db: mockDb as any,
|
||
});
|
||
|
||
expect(result).toHaveLength(1);
|
||
expect(result[0].teamId).toBe(TEAM_ID);
|
||
expect(result[0].removedParticipantIds).toEqual(["p-snooker"]);
|
||
expect(mockDelete).toHaveBeenCalledTimes(1);
|
||
});
|
||
|
||
it("returns empty array when all teams still have their sports eligible", async () => {
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([
|
||
{ id: "p-snooker", name: "Ronnie O'Sullivan", sport: { id: "sport-snooker", name: "Snooker" } },
|
||
] as any);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue(
|
||
{ eligibleSportIds: new Set(["sport-snooker"]) } as any
|
||
);
|
||
|
||
vi.mocked(getAllQueuesForSeason).mockResolvedValue(
|
||
makeSeasonQueues([
|
||
[TEAM_ID, [{ id: "q-1", participantId: "p-snooker", queuePosition: 1 }]],
|
||
["team-2", [{ id: "q-2", participantId: "p-snooker", queuePosition: 1 }]],
|
||
])
|
||
);
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockDb = makeMockDb({ delete: mockDelete });
|
||
|
||
const result = await pruneIneligibleQueueItems({
|
||
seasonId: SEASON_ID,
|
||
draftRounds: DRAFT_ROUNDS,
|
||
allTeamIds: ALL_TEAM_IDS,
|
||
db: mockDb as any,
|
||
});
|
||
|
||
expect(result).toHaveLength(0);
|
||
expect(mockDelete).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it("skips teams with empty queues and does not call delete", async () => {
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([]);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue(
|
||
{ eligibleSportIds: new Set([]) } as any
|
||
);
|
||
|
||
// Both teams return no queue items from the single bulk fetch
|
||
vi.mocked(getAllQueuesForSeason).mockResolvedValue(new Map());
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockDb = makeMockDb({ delete: mockDelete });
|
||
|
||
const result = await pruneIneligibleQueueItems({
|
||
seasonId: SEASON_ID,
|
||
draftRounds: DRAFT_ROUNDS,
|
||
allTeamIds: ALL_TEAM_IDS,
|
||
db: mockDb as any,
|
||
});
|
||
|
||
expect(result).toHaveLength(0);
|
||
expect(mockDelete).not.toHaveBeenCalled();
|
||
// The bulk fetch replaces per-team queries — getTeamQueue should never be called
|
||
expect(vi.mocked(getTeamQueue)).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it("prunes only the ineligible items when a team has a mixed queue", async () => {
|
||
// Team has two queued players: snooker (ineligible) and NFL (still eligible)
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([
|
||
{ id: "p-snooker", name: "Ronnie O'Sullivan", sport: { id: "sport-snooker", name: "Snooker" } },
|
||
{ id: "p-nfl", name: "Patrick Mahomes", sport: { id: "sport-nfl", name: "NFL" } },
|
||
] as any);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue(
|
||
{ eligibleSportIds: new Set(["sport-nfl"]) } as any // snooker full, NFL still ok
|
||
);
|
||
|
||
vi.mocked(getAllQueuesForSeason).mockResolvedValue(
|
||
makeSeasonQueues([
|
||
[TEAM_ID, [
|
||
{ id: "q-snooker", participantId: "p-snooker", queuePosition: 1 },
|
||
{ id: "q-nfl", participantId: "p-nfl", queuePosition: 2 },
|
||
]],
|
||
])
|
||
);
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockWhere = vi.fn().mockResolvedValue(undefined);
|
||
const mockDb = makeMockDb({ delete: mockDelete, where: mockWhere });
|
||
|
||
const result = await pruneIneligibleQueueItems({
|
||
seasonId: SEASON_ID,
|
||
draftRounds: DRAFT_ROUNDS,
|
||
allTeamIds: [TEAM_ID],
|
||
db: mockDb as any,
|
||
});
|
||
|
||
expect(result).toHaveLength(1);
|
||
expect(result[0].removedParticipantIds).toEqual(["p-snooker"]);
|
||
// The NFL player must NOT be removed
|
||
expect(result[0].removedParticipantIds).not.toContain("p-nfl");
|
||
expect(mockDelete).toHaveBeenCalledTimes(1);
|
||
});
|
||
|
||
it("skips a queue item whose participant is not found in season sports and logs a warning", async () => {
|
||
vi.mocked(getDraftPicksWithSports).mockResolvedValue([]);
|
||
// allParticipants does NOT include p-mystery
|
||
vi.mocked(getParticipantsForSeasonWithSports).mockResolvedValue([]);
|
||
vi.mocked(getSeasonSportsSimple).mockResolvedValue([]);
|
||
vi.mocked(calculateDraftEligibility).mockReturnValue(
|
||
{ eligibleSportIds: new Set([]) } as any
|
||
);
|
||
|
||
vi.mocked(getAllQueuesForSeason).mockResolvedValue(
|
||
makeSeasonQueues([
|
||
[TEAM_ID, [{ id: "q-mystery", participantId: "p-mystery", queuePosition: 1 }]],
|
||
])
|
||
);
|
||
|
||
const mockDelete = vi.fn().mockReturnThis();
|
||
const mockDb = makeMockDb({ delete: mockDelete });
|
||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||
|
||
const result = await pruneIneligibleQueueItems({
|
||
seasonId: SEASON_ID,
|
||
draftRounds: DRAFT_ROUNDS,
|
||
allTeamIds: [TEAM_ID],
|
||
db: mockDb as any,
|
||
});
|
||
|
||
// Item is skipped — not deleted, not returned
|
||
expect(result).toHaveLength(0);
|
||
expect(mockDelete).not.toHaveBeenCalled();
|
||
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("p-mystery"));
|
||
|
||
warnSpy.mockRestore();
|
||
});
|
||
});
|