brackt/app/models/__tests__/sports-season.test.ts
Chris Parsons dc879e3033
feat: sort admin sports seasons by status, sport name, then year (#286)
Active seasons sort first, then upcoming, then completed. Within each
status group, seasons sort by sport name alphabetically then year
ascending. Fixes return type of findAllSportsSeasons to reflect the
included sport/participants relations, removing the cast in the loader.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 10:07:18 -04:00

127 lines
5.3 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("~/database/context", () => ({
database: vi.fn(),
}));
// Mock the schema so the schema module doesn't execute drizzle builder calls,
// following the same pattern as scoring-event-dashboard.test.ts.
vi.mock("~/database/schema", () => ({
sportsSeasons: {
id: "ss.id",
sportId: "ss.sport_id",
name: "ss.name",
year: "ss.year",
draftOn: "ss.draft_on",
draftOff: "ss.draft_off",
},
}));
vi.mock("drizzle-orm", () => ({
eq: (col: unknown, val: unknown) => ({ type: "eq", col, val }),
sql: (strings: TemplateStringsArray, ...values: unknown[]) => ({ type: "sql", strings, values }),
lte: (col: unknown, val: unknown) => ({ type: "lte", col, val }),
gte: (col: unknown, val: unknown) => ({ type: "gte", col, val }),
and: (...args: unknown[]) => ({ type: "and", args }),
desc: (col: unknown) => ({ type: "desc", col }),
asc: (col: unknown) => ({ type: "asc", col }),
}));
import { findAllSportsSeasons, findDraftableSportsSeasons } from "../sports-season";
import { database } from "~/database/context";
const today = new Date().toISOString().slice(0, 10);
const future = "2099-12-31";
const pastStart = "2020-01-01";
const pastEnd = "2020-12-31";
const mockSeasons = [
{ id: "season-1", name: "2025 NBA Playoffs", draftOn: today, draftOff: future, year: 2025, status: "upcoming", sport: { name: "NBA" } },
{ id: "season-2", name: "2025 F1 Season", draftOn: today, draftOff: future, year: 2025, status: "upcoming", sport: { name: "F1" } },
{ id: "season-3", name: "2024 Old Golf", draftOn: pastStart, draftOff: pastEnd, year: 2024, status: "completed", sport: { name: "Golf" } },
];
function makeMockDb(seasons: typeof mockSeasons) {
return {
query: {
sportsSeasons: {
findMany: vi.fn().mockResolvedValue(seasons),
},
},
};
}
beforeEach(() => {
vi.clearAllMocks();
});
describe("findAllSportsSeasons", () => {
it("returns all sport seasons regardless of draft window", async () => {
vi.mocked(database).mockReturnValue(makeMockDb(mockSeasons) as never);
const result = await findAllSportsSeasons();
expect(result).toHaveLength(3);
});
it("sorts active before upcoming before completed", async () => {
const seasons = [
{ id: "s1", name: "Completed", draftOn: pastStart, draftOff: pastEnd, year: 2024, status: "completed", sport: { name: "Sport" } },
{ id: "s2", name: "Active", draftOn: today, draftOff: future, year: 2025, status: "active", sport: { name: "Sport" } },
{ id: "s3", name: "Upcoming", draftOn: today, draftOff: future, year: 2026, status: "upcoming", sport: { name: "Sport" } },
];
vi.mocked(database).mockReturnValue(makeMockDb(seasons) as never);
const result = await findAllSportsSeasons();
expect(result.map((s) => s.status)).toEqual(["active", "upcoming", "completed"]);
});
it("sorts by sport name alphabetically within the same status", async () => {
const seasons = [
{ id: "s1", name: "Zebra Season", draftOn: today, draftOff: future, year: 2025, status: "active", sport: { name: "Zebra" } },
{ id: "s2", name: "Apple Season", draftOn: today, draftOff: future, year: 2025, status: "active", sport: { name: "Apple" } },
{ id: "s3", name: "Mango Season", draftOn: today, draftOff: future, year: 2025, status: "active", sport: { name: "Mango" } },
];
vi.mocked(database).mockReturnValue(makeMockDb(seasons) as never);
const result = await findAllSportsSeasons();
expect(result.map((s) => s.sport.name)).toEqual(["Apple", "Mango", "Zebra"]);
});
it("sorts by year ascending within the same status and sport name", async () => {
const seasons = [
{ id: "s1", name: "NFL 2026", draftOn: today, draftOff: future, year: 2026, status: "upcoming", sport: { name: "NFL" } },
{ id: "s2", name: "NFL 2024", draftOn: today, draftOff: future, year: 2024, status: "upcoming", sport: { name: "NFL" } },
{ id: "s3", name: "NFL 2025", draftOn: today, draftOff: future, year: 2025, status: "upcoming", sport: { name: "NFL" } },
];
vi.mocked(database).mockReturnValue(makeMockDb(seasons) as never);
const result = await findAllSportsSeasons();
expect(result.map((s) => s.year)).toEqual([2024, 2025, 2026]);
});
});
describe("findDraftableSportsSeasons", () => {
it("returns only currently-draftable seasons", async () => {
const draftableOnly = mockSeasons.filter((s) => s.draftOn <= today && today <= s.draftOff);
const mockDb = makeMockDb(draftableOnly);
vi.mocked(database).mockReturnValue(mockDb as never);
const result = await findDraftableSportsSeasons();
expect(result).toHaveLength(2);
expect(result.every((s) => s.draftOn <= today && today <= s.draftOff)).toBe(true);
});
it("returns empty array when no seasons fall within a draft window", async () => {
vi.mocked(database).mockReturnValue(makeMockDb([]) as never);
const result = await findDraftableSportsSeasons();
expect(result).toHaveLength(0);
});
it("calls findMany with a where clause", async () => {
const mockDb = makeMockDb([]);
vi.mocked(database).mockReturnValue(mockDb as never);
await findDraftableSportsSeasons();
expect(mockDb.query.sportsSeasons.findMany).toHaveBeenCalledWith(
expect.objectContaining({
where: expect.anything(),
})
);
});
});