225 lines
7.5 KiB
TypeScript
225 lines
7.5 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
// ── DB mock ────────────────────────────────────────────────────────────────
|
|
|
|
const DEFAULT_SEASON = {
|
|
id: "season-1",
|
|
pointsFor1st: 100, pointsFor2nd: 75, pointsFor3rd: 50,
|
|
pointsFor4th: 40, pointsFor5th: 30, pointsFor6th: 20,
|
|
pointsFor7th: 10, pointsFor8th: 5,
|
|
};
|
|
|
|
type PickRow = {
|
|
participant: {
|
|
id: string;
|
|
name: string;
|
|
sportsSeasonId: string;
|
|
sportsSeason: { id: string; scoringPattern: string };
|
|
results: { finalPosition: number | null }[];
|
|
};
|
|
};
|
|
|
|
interface MakeDbOpts {
|
|
season?: typeof DEFAULT_SEASON | null;
|
|
picks?: PickRow[];
|
|
scoringEvents?: { sportsSeasonId: string; bracketTemplateId: string | null }[];
|
|
qualifyingTotals?: { participantId: string; totalQualifyingPoints: string }[];
|
|
}
|
|
|
|
function makeDb(opts: MakeDbOpts = {}) {
|
|
const {
|
|
season = DEFAULT_SEASON,
|
|
picks = [],
|
|
scoringEvents = [],
|
|
qualifyingTotals = [],
|
|
} = opts;
|
|
|
|
return {
|
|
query: {
|
|
seasons: {
|
|
findFirst: vi.fn().mockResolvedValue(season),
|
|
},
|
|
draftPicks: {
|
|
findMany: vi.fn().mockResolvedValue(picks),
|
|
},
|
|
scoringEvents: {
|
|
findMany: vi.fn().mockResolvedValue(scoringEvents),
|
|
},
|
|
seasonParticipantQualifyingTotals: {
|
|
findMany: vi.fn().mockResolvedValue(qualifyingTotals),
|
|
},
|
|
},
|
|
} as any;
|
|
}
|
|
|
|
import { getDraftedParticipantsWithPoints } from "../draft-pick";
|
|
|
|
function makePick(overrides: {
|
|
id?: string;
|
|
name?: string;
|
|
sportsSeasonId?: string;
|
|
scoringPattern?: string;
|
|
finalPosition?: number | null;
|
|
}): PickRow {
|
|
const {
|
|
id = "p-1",
|
|
name = "Participant One",
|
|
sportsSeasonId = "ss-1",
|
|
scoringPattern = "playoff_bracket",
|
|
finalPosition = null,
|
|
} = overrides;
|
|
return {
|
|
participant: {
|
|
id,
|
|
name,
|
|
sportsSeasonId,
|
|
sportsSeason: { id: sportsSeasonId, scoringPattern },
|
|
results: finalPosition !== null ? [{ finalPosition }] : [],
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("getDraftedParticipantsWithPoints", () => {
|
|
beforeEach(() => vi.clearAllMocks());
|
|
|
|
it("returns empty map when season not found", async () => {
|
|
const db = makeDb({ season: null });
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
expect(result.size).toBe(0);
|
|
});
|
|
|
|
it("returns empty map when no picks", async () => {
|
|
const db = makeDb({ picks: [] });
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
expect(result.size).toBe(0);
|
|
});
|
|
|
|
describe("playoff_bracket pattern", () => {
|
|
it("returns earnedPoints based on finalPosition and scoring rules", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ scoringPattern: "playoff_bracket", finalPosition: 1 })],
|
|
scoringEvents: [{ sportsSeasonId: "ss-1", bracketTemplateId: null }],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
const ssEntry = result.get("ss-1");
|
|
expect(ssEntry).toBeDefined();
|
|
expect(ssEntry?.[0]).toMatchObject({
|
|
id: "p-1",
|
|
name: "Participant One",
|
|
earnedPoints: 100, // pointsFor1st
|
|
currentQP: null,
|
|
});
|
|
});
|
|
|
|
it("returns null earnedPoints when no finalPosition yet", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ scoringPattern: "playoff_bracket", finalPosition: null })],
|
|
scoringEvents: [{ sportsSeasonId: "ss-1", bracketTemplateId: null }],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(result.get("ss-1")?.[0]).toMatchObject({ earnedPoints: null, currentQP: null });
|
|
});
|
|
|
|
it("groups multiple picks by sportsSeasonId", async () => {
|
|
const db = makeDb({
|
|
picks: [
|
|
makePick({ id: "p-1", name: "Alice", sportsSeasonId: "ss-1", scoringPattern: "playoff_bracket", finalPosition: 1 }),
|
|
makePick({ id: "p-2", name: "Bob", sportsSeasonId: "ss-1", scoringPattern: "playoff_bracket", finalPosition: 2 }),
|
|
makePick({ id: "p-3", name: "Carol", sportsSeasonId: "ss-2", scoringPattern: "playoff_bracket", finalPosition: 1 }),
|
|
],
|
|
scoringEvents: [
|
|
{ sportsSeasonId: "ss-1", bracketTemplateId: null },
|
|
{ sportsSeasonId: "ss-2", bracketTemplateId: null },
|
|
],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(result.get("ss-1")).toHaveLength(2);
|
|
expect(result.get("ss-2")).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe("qualifying_points pattern — active (no finalPosition)", () => {
|
|
it("returns currentQP from participantQualifyingTotals", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: null })],
|
|
qualifyingTotals: [{ participantId: "p-1", totalQualifyingPoints: "42.5" }],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(result.get("ss-1")?.[0]).toMatchObject({
|
|
earnedPoints: null,
|
|
currentQP: 42.5,
|
|
});
|
|
});
|
|
|
|
it("returns null currentQP when participant has no QP total row", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: null })],
|
|
qualifyingTotals: [],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(result.get("ss-1")?.[0]).toMatchObject({ earnedPoints: null, currentQP: null });
|
|
});
|
|
});
|
|
|
|
describe("qualifying_points pattern — finalized (has finalPosition)", () => {
|
|
it("returns earnedPoints via calculateFantasyPoints when finalPosition set", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: 2 })],
|
|
qualifyingTotals: [{ participantId: "p-1", totalQualifyingPoints: "99" }],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(result.get("ss-1")?.[0]).toMatchObject({
|
|
earnedPoints: 75, // pointsFor2nd
|
|
currentQP: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("season_standings pattern", () => {
|
|
it("returns earnedPoints via calculateFantasyPoints", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "season_standings", finalPosition: 3 })],
|
|
});
|
|
|
|
const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(result.get("ss-1")?.[0]).toMatchObject({
|
|
earnedPoints: 50, // pointsFor3rd
|
|
currentQP: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
it("does not query scoringEvents when no playoff_bracket picks", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ scoringPattern: "season_standings", finalPosition: 1 })],
|
|
});
|
|
|
|
await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(db.query.scoringEvents.findMany).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("does not query participantQualifyingTotals when no qualifying_points picks", async () => {
|
|
const db = makeDb({
|
|
picks: [makePick({ scoringPattern: "playoff_bracket", finalPosition: null })],
|
|
scoringEvents: [{ sportsSeasonId: "ss-1", bracketTemplateId: null }],
|
|
});
|
|
|
|
await getDraftedParticipantsWithPoints("team-1", "season-1", db);
|
|
|
|
expect(db.query.participantQualifyingTotals.findMany).not.toHaveBeenCalled();
|
|
});
|
|
});
|