brackt/app/models/__tests__/scoring-event-dashboard.test.ts

185 lines
6.3 KiB
TypeScript
Raw Normal View History

/**
* Tests for getEventsForDates the admin dashboard "Games to Score" query.
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
// ── DB mock ─────────────────────────────────────────────────────────────────
const mockFindMany = vi.fn();
const mockDb = {
query: {
scoringEvents: { findMany: mockFindMany },
},
};
vi.mock("~/database/context", () => ({
database: () => mockDb,
}));
vi.mock("~/database/schema", () => ({
scoringEvents: {
eventDate: "se.event_date",
eventType: "se.event_type",
eventStartsAt: "se.event_starts_at",
createdAt: "se.created_at",
},
}));
vi.mock("drizzle-orm", () => ({
eq: (col: unknown, val: unknown) => ({ type: "eq", col, val }),
and: (...args: unknown[]) => ({ type: "and", args }),
asc: (col: unknown) => ({ type: "asc", col }),
desc: (col: unknown) => ({ type: "desc", col }),
gte: (col: unknown, val: unknown) => ({ type: "gte", col, val }),
lte: (col: unknown, val: unknown) => ({ type: "lte", col, val }),
or: (...args: unknown[]) => ({ type: "or", args }),
inArray: (col: unknown, arr: unknown) => ({ type: "inArray", col, arr }),
isNotNull: (col: unknown) => ({ type: "isNotNull", col }),
}));
// Must be imported after mocks are registered
import { getEventsForDates } from "../scoring-event";
// ── Helpers ──────────────────────────────────────────────────────────────────
function makeScoringEventRow(overrides: Partial<{
id: string;
name: string;
eventDate: string | null;
eventStartsAt: Date | null;
eventType: string;
isComplete: boolean;
completedAt: Date | null;
sportsSeasonId: string;
sportsSeason: { name: string; sport: { name: string; slug: string | null } };
}> = {}) {
return {
id: overrides.id ?? "event-1",
name: overrides.name ?? "Test Event",
eventDate: overrides.eventDate ?? "2026-03-20",
eventStartsAt: overrides.eventStartsAt ?? null,
eventType: overrides.eventType ?? "playoff_game",
isComplete: overrides.isComplete ?? false,
completedAt: overrides.completedAt ?? null,
sportsSeasonId: overrides.sportsSeasonId ?? "season-1",
sportsSeason: overrides.sportsSeason ?? {
name: "2026 NFL Playoffs",
sport: { name: "NFL", slug: "nfl" },
},
};
}
// ── Tests ────────────────────────────────────────────────────────────────────
describe("getEventsForDates", () => {
beforeEach(() => {
mockFindMany.mockReset();
});
it("returns an empty array when no dates are provided", async () => {
const result = await getEventsForDates([]);
expect(result).toEqual([]);
expect(mockFindMany).not.toHaveBeenCalled();
});
it("maps database rows to DashboardScoringEvent shape", async () => {
const row = makeScoringEventRow({
id: "e1",
name: "Conference Finals",
eventDate: "2026-03-20",
eventType: "playoff_game",
isComplete: false,
sportsSeasonId: "ss-1",
sportsSeason: {
name: "2026 NBA Playoffs",
sport: { name: "NBA", slug: "nba" },
},
});
mockFindMany.mockResolvedValueOnce([row]);
const result = await getEventsForDates(["2026-03-20"]);
expect(result).toHaveLength(1);
expect(result[0]).toMatchObject({
id: "e1",
name: "Conference Finals",
eventDate: "2026-03-20",
eventType: "playoff_game",
isComplete: false,
sportsSeasonId: "ss-1",
sportsSeasonName: "2026 NBA Playoffs",
sportName: "NBA",
sportSlug: "nba",
});
});
it("returns events for multiple dates", async () => {
const todayRow = makeScoringEventRow({ id: "e1", eventDate: "2026-03-20" });
const tomorrowRow = makeScoringEventRow({ id: "e2", eventDate: "2026-03-21" });
mockFindMany.mockResolvedValueOnce([todayRow, tomorrowRow]);
const result = await getEventsForDates(["2026-03-20", "2026-03-21"]);
expect(result).toHaveLength(2);
expect(result.map((e) => e.id)).toEqual(["e1", "e2"]);
});
it("includes completed events with isComplete: true", async () => {
const completedRow = makeScoringEventRow({
id: "e-done",
isComplete: true,
completedAt: new Date("2026-03-20T18:00:00Z"),
});
mockFindMany.mockResolvedValueOnce([completedRow]);
const result = await getEventsForDates(["2026-03-20"]);
expect(result[0].isComplete).toBe(true);
expect(result[0].completedAt).toBeInstanceOf(Date);
});
it("includes eventStartsAt when present", async () => {
const starts = new Date("2026-03-20T19:30:00Z");
const row = makeScoringEventRow({ id: "e1", eventStartsAt: starts });
mockFindMany.mockResolvedValueOnce([row]);
const result = await getEventsForDates(["2026-03-20"]);
expect(result[0].eventStartsAt).toEqual(starts);
});
it("passes both dates as an inArray condition to the query", async () => {
mockFindMany.mockResolvedValueOnce([]);
await getEventsForDates(["2026-03-20", "2026-03-21"]);
const callArgs = mockFindMany.mock.calls[0][0];
// The where clause should contain an inArray condition with both dates
const whereStr = JSON.stringify(callArgs.where);
expect(whereStr).toContain("2026-03-20");
expect(whereStr).toContain("2026-03-21");
});
it("excludes schedule_event types via inArray condition", async () => {
mockFindMany.mockResolvedValueOnce([]);
await getEventsForDates(["2026-03-20"]);
const callArgs = mockFindMany.mock.calls[0][0];
const whereStr = JSON.stringify(callArgs.where);
// The allowed event types should be present
expect(whereStr).toContain("playoff_game");
expect(whereStr).toContain("major_tournament");
expect(whereStr).toContain("final_standings");
// schedule_event should not appear
expect(whereStr).not.toContain("schedule_event");
});
it("returns empty array when DB returns no rows", async () => {
mockFindMany.mockResolvedValueOnce([]);
const result = await getEventsForDates(["2026-03-20"]);
expect(result).toEqual([]);
});
});