Fix scoring-event-dashboard tests after select/sql changes

- Rename mockSelectDistinct → mockSelect to match implementation change
  from .selectDistinct() to .select()
- Add sql to drizzle-orm mock
- Update mock row shapes to include eventDate and gameDate fields
- Add two tests covering displayDate derivation from eventDate and gameDate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Parsons 2026-03-25 20:41:46 -07:00
parent fac61fdcdf
commit 095f351cb1

View file

@ -4,10 +4,10 @@
import { describe, it, expect, vi, beforeEach } from "vitest"; import { describe, it, expect, vi, beforeEach } from "vitest";
// ── DB mock ────────────────────────────────────────────────────────────────── // ── DB mock ──────────────────────────────────────────────────────────────────
// selectDistinct returns a fluent chain; findMany is used in step 2. // select returns a fluent chain; findMany is used in step 2.
const mockFindMany = vi.fn(); const mockFindMany = vi.fn();
function makeSelectChain(rows: { id: string }[]) { function makeSelectChain(rows: { id: string; eventDate?: string | null; gameDate?: string | null }[]) {
const chain = { const chain = {
from: vi.fn().mockReturnThis(), from: vi.fn().mockReturnThis(),
leftJoin: vi.fn().mockReturnThis(), leftJoin: vi.fn().mockReturnThis(),
@ -16,13 +16,13 @@ function makeSelectChain(rows: { id: string }[]) {
return chain; return chain;
} }
const mockSelectDistinct = vi.fn(); const mockSelect = vi.fn();
const mockDb = { const mockDb = {
query: { query: {
scoringEvents: { findMany: mockFindMany }, scoringEvents: { findMany: mockFindMany },
}, },
selectDistinct: mockSelectDistinct, select: mockSelect,
}; };
vi.mock("~/database/context", () => ({ vi.mock("~/database/context", () => ({
@ -57,6 +57,7 @@ vi.mock("drizzle-orm", () => ({
or: (...args: unknown[]) => ({ type: "or", args }), or: (...args: unknown[]) => ({ type: "or", args }),
inArray: (col: unknown, arr: unknown) => ({ type: "inArray", col, arr }), inArray: (col: unknown, arr: unknown) => ({ type: "inArray", col, arr }),
isNotNull: (col: unknown) => ({ type: "isNotNull", col }), isNotNull: (col: unknown) => ({ type: "isNotNull", col }),
sql: (strings: TemplateStringsArray, ...values: unknown[]) => ({ type: "sql", strings, values }),
})); }));
import { getEventsForDates } from "../scoring-event"; import { getEventsForDates } from "../scoring-event";
@ -95,18 +96,18 @@ function makeEventRow(overrides: Partial<{
describe("getEventsForDates", () => { describe("getEventsForDates", () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
mockSelectDistinct.mockReturnValue(makeSelectChain([])); mockSelect.mockReturnValue(makeSelectChain([]));
}); });
it("returns empty array and skips DB when no dates given", async () => { it("returns empty array and skips DB when no dates given", async () => {
const result = await getEventsForDates([]); const result = await getEventsForDates([]);
expect(result).toEqual([]); expect(result).toEqual([]);
expect(mockSelectDistinct).not.toHaveBeenCalled(); expect(mockSelect).not.toHaveBeenCalled();
expect(mockFindMany).not.toHaveBeenCalled(); expect(mockFindMany).not.toHaveBeenCalled();
}); });
it("returns empty array when selectDistinct finds no matching event IDs", async () => { it("returns empty array when select finds no matching event IDs", async () => {
mockSelectDistinct.mockReturnValue(makeSelectChain([])); mockSelect.mockReturnValue(makeSelectChain([]));
const result = await getEventsForDates(["2026-03-20"]); const result = await getEventsForDates(["2026-03-20"]);
@ -115,7 +116,7 @@ describe("getEventsForDates", () => {
}); });
it("maps database rows to DashboardScoringEvent shape", async () => { it("maps database rows to DashboardScoringEvent shape", async () => {
mockSelectDistinct.mockReturnValue(makeSelectChain([{ id: "e1" }])); mockSelect.mockReturnValue(makeSelectChain([{ id: "e1", eventDate: "2026-03-20", gameDate: null }]));
mockFindMany.mockResolvedValueOnce([ mockFindMany.mockResolvedValueOnce([
makeEventRow({ makeEventRow({
id: "e1", id: "e1",
@ -148,8 +149,8 @@ describe("getEventsForDates", () => {
}); });
it("returns events for multiple dates", async () => { it("returns events for multiple dates", async () => {
mockSelectDistinct.mockReturnValue( mockSelect.mockReturnValue(
makeSelectChain([{ id: "e1" }, { id: "e2" }]) makeSelectChain([{ id: "e1", eventDate: "2026-03-20", gameDate: null }, { id: "e2", eventDate: "2026-03-21", gameDate: null }])
); );
mockFindMany.mockResolvedValueOnce([ mockFindMany.mockResolvedValueOnce([
makeEventRow({ id: "e1", eventDate: "2026-03-20" }), makeEventRow({ id: "e1", eventDate: "2026-03-20" }),
@ -163,7 +164,7 @@ describe("getEventsForDates", () => {
}); });
it("includes completed events with isComplete: true", async () => { it("includes completed events with isComplete: true", async () => {
mockSelectDistinct.mockReturnValue(makeSelectChain([{ id: "e-done" }])); mockSelect.mockReturnValue(makeSelectChain([{ id: "e-done", eventDate: "2026-03-20", gameDate: null }]));
mockFindMany.mockResolvedValueOnce([ mockFindMany.mockResolvedValueOnce([
makeEventRow({ makeEventRow({
id: "e-done", id: "e-done",
@ -180,7 +181,7 @@ describe("getEventsForDates", () => {
it("includes eventStartsAt when present", async () => { it("includes eventStartsAt when present", async () => {
const starts = new Date("2026-03-20T19:30:00Z"); const starts = new Date("2026-03-20T19:30:00Z");
mockSelectDistinct.mockReturnValue(makeSelectChain([{ id: "e1" }])); mockSelect.mockReturnValue(makeSelectChain([{ id: "e1", eventDate: "2026-03-20", gameDate: null }]));
mockFindMany.mockResolvedValueOnce([ mockFindMany.mockResolvedValueOnce([
makeEventRow({ id: "e1", eventStartsAt: starts }), makeEventRow({ id: "e1", eventStartsAt: starts }),
]); ]);
@ -190,19 +191,19 @@ describe("getEventsForDates", () => {
expect(result[0].eventStartsAt).toEqual(starts); expect(result[0].eventStartsAt).toEqual(starts);
}); });
it("uses two DB calls: selectDistinct then findMany", async () => { it("uses two DB calls: select then findMany", async () => {
mockSelectDistinct.mockReturnValue(makeSelectChain([{ id: "e1" }])); mockSelect.mockReturnValue(makeSelectChain([{ id: "e1", eventDate: "2026-03-20", gameDate: null }]));
mockFindMany.mockResolvedValueOnce([makeEventRow({ id: "e1" })]); mockFindMany.mockResolvedValueOnce([makeEventRow({ id: "e1" })]);
await getEventsForDates(["2026-03-20"]); await getEventsForDates(["2026-03-20"]);
expect(mockSelectDistinct).toHaveBeenCalledOnce(); expect(mockSelect).toHaveBeenCalledOnce();
expect(mockFindMany).toHaveBeenCalledOnce(); expect(mockFindMany).toHaveBeenCalledOnce();
}); });
it("passes event IDs from step 1 into findMany in step 2", async () => { it("passes event IDs from step 1 into findMany in step 2", async () => {
mockSelectDistinct.mockReturnValue( mockSelect.mockReturnValue(
makeSelectChain([{ id: "abc" }, { id: "def" }]) makeSelectChain([{ id: "abc", eventDate: "2026-03-20", gameDate: null }, { id: "def", eventDate: "2026-03-20", gameDate: null }])
); );
mockFindMany.mockResolvedValueOnce([]); mockFindMany.mockResolvedValueOnce([]);
@ -216,7 +217,7 @@ describe("getEventsForDates", () => {
it("uses leftJoin so bracket events without playoffMatchGames still qualify via eventDate", async () => { it("uses leftJoin so bracket events without playoffMatchGames still qualify via eventDate", async () => {
const chain = makeSelectChain([]); const chain = makeSelectChain([]);
mockSelectDistinct.mockReturnValue(chain); mockSelect.mockReturnValue(chain);
await getEventsForDates(["2026-03-20"]); await getEventsForDates(["2026-03-20"]);
@ -225,7 +226,7 @@ describe("getEventsForDates", () => {
it("includes both eventDate and scheduledAt timestamp bounds in the where clause", async () => { it("includes both eventDate and scheduledAt timestamp bounds in the where clause", async () => {
const chain = makeSelectChain([]); const chain = makeSelectChain([]);
mockSelectDistinct.mockReturnValue(chain); mockSelect.mockReturnValue(chain);
await getEventsForDates(["2026-03-20", "2026-03-21"]); await getEventsForDates(["2026-03-20", "2026-03-21"]);
@ -241,7 +242,7 @@ describe("getEventsForDates", () => {
it("excludes schedule_event type via the where clause", async () => { it("excludes schedule_event type via the where clause", async () => {
const chain = makeSelectChain([]); const chain = makeSelectChain([]);
mockSelectDistinct.mockReturnValue(chain); mockSelect.mockReturnValue(chain);
await getEventsForDates(["2026-03-20"]); await getEventsForDates(["2026-03-20"]);
@ -251,4 +252,22 @@ describe("getEventsForDates", () => {
expect(whereArg).toContain("final_standings"); expect(whereArg).toContain("final_standings");
expect(whereArg).not.toContain("schedule_event"); expect(whereArg).not.toContain("schedule_event");
}); });
it("sets displayDate from eventDate when present", async () => {
mockSelect.mockReturnValue(makeSelectChain([{ id: "e1", eventDate: "2026-03-20", gameDate: null }]));
mockFindMany.mockResolvedValueOnce([makeEventRow({ id: "e1", eventDate: "2026-03-20" })]);
const result = await getEventsForDates(["2026-03-20"]);
expect(result[0].displayDate).toBe("2026-03-20");
});
it("sets displayDate from gameDate when eventDate is null", async () => {
mockSelect.mockReturnValue(makeSelectChain([{ id: "e1", eventDate: null, gameDate: "2026-03-20" }]));
mockFindMany.mockResolvedValueOnce([makeEventRow({ id: "e1", eventDate: null })]);
const result = await getEventsForDates(["2026-03-20"]);
expect(result[0].displayDate).toBe("2026-03-20");
});
}); });