brackt/app/models/__tests__/golf-skills.test.ts

166 lines
5.2 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("~/database/context", () => ({
database: vi.fn(),
}));
import { database } from "~/database/context";
import { getGolfSkillsForSeason, getGolfSkillsMap, batchUpsertGolfSkills } from "../golf-skills";
const mockDb = {
select: vi.fn().mockReturnThis(),
from: vi.fn().mockReturnThis(),
where: vi.fn().mockReturnThis(),
innerJoin: vi.fn().mockReturnThis(),
leftJoin: vi.fn().mockReturnThis(),
orderBy: vi.fn().mockReturnThis(),
insert: vi.fn().mockReturnThis(),
values: vi.fn().mockReturnThis(),
onConflictDoUpdate: vi.fn().mockReturnThis(),
};
beforeEach(() => {
vi.clearAllMocks();
(database as ReturnType<typeof vi.fn>).mockReturnValue(mockDb);
mockDb.select.mockReturnValue(mockDb);
mockDb.from.mockReturnValue(mockDb);
mockDb.where.mockReturnValue(mockDb);
mockDb.innerJoin.mockReturnValue(mockDb);
mockDb.leftJoin.mockReturnValue(mockDb);
mockDb.orderBy.mockReturnValue(mockDb);
mockDb.insert.mockReturnValue(mockDb);
mockDb.values.mockReturnValue(mockDb);
mockDb.onConflictDoUpdate.mockResolvedValue(undefined);
});
describe("getGolfSkillsMap", () => {
it("returns an empty Map when no records exist", async () => {
mockDb.where.mockResolvedValue([]);
const result = await getGolfSkillsMap("season-1");
expect(result).toBeInstanceOf(Map);
expect(result.size).toBe(0);
});
it("returns a Map keyed by seasonParticipantId with sgTotal converted to number", async () => {
mockDb.where.mockResolvedValue([
{
seasonParticipantId: "sp-1",
sportsSeasonId: "season-1",
id: "skill-1",
sgTotal: "2.50",
datagolfRank: 3,
mastersOdds: 800,
usOpenOdds: null,
openChampionshipOdds: null,
pgaChampionshipOdds: null,
updatedAt: new Date("2026-01-01"),
},
]);
const result = await getGolfSkillsMap("season-1");
expect(result.size).toBe(1);
const record = result.get("sp-1");
expect(record).toBeDefined();
expect(record?.sgTotal).toBe(2.5);
expect(record?.participantId).toBe("sp-1");
expect(record?.mastersOdds).toBe(800);
});
it("preserves null sgTotal", async () => {
mockDb.where.mockResolvedValue([
{
seasonParticipantId: "sp-1",
sportsSeasonId: "season-1",
id: "skill-1",
sgTotal: null,
datagolfRank: null,
mastersOdds: null,
usOpenOdds: null,
openChampionshipOdds: null,
pgaChampionshipOdds: null,
updatedAt: new Date("2026-01-01"),
},
]);
const result = await getGolfSkillsMap("season-1");
expect(result.get("sp-1")?.sgTotal).toBeNull();
});
});
describe("getGolfSkillsForSeason", () => {
it("returns records joined with participant names and converts sgTotal", async () => {
mockDb.orderBy.mockResolvedValue([
{
id: "skill-1",
participantId: "sp-1",
sportsSeasonId: "season-1",
sgTotal: "1.24",
datagolfRank: 10,
mastersOdds: 400,
usOpenOdds: null,
openChampionshipOdds: null,
pgaChampionshipOdds: null,
updatedAt: new Date("2026-01-01"),
participantName: "Rory McIlroy",
},
]);
const result = await getGolfSkillsForSeason("season-1");
expect(result).toHaveLength(1);
expect(result[0].participantName).toBe("Rory McIlroy");
expect(result[0].sgTotal).toBe(1.24);
expect(result[0].mastersOdds).toBe(400);
});
it("returns empty array when no records exist", async () => {
mockDb.orderBy.mockResolvedValue([]);
const result = await getGolfSkillsForSeason("season-1");
expect(result).toEqual([]);
});
});
describe("batchUpsertGolfSkills", () => {
it("does nothing when given an empty array", async () => {
await batchUpsertGolfSkills([]);
expect(mockDb.insert).not.toHaveBeenCalled();
});
it("writes canonical rows using resolved canonical participant ids", async () => {
mockDb.where.mockResolvedValueOnce([
{ id: "sp-1", canonicalId: "canon-1" },
{ id: "sp-2", canonicalId: "canon-2" },
]);
await batchUpsertGolfSkills([
{ participantId: "sp-1", sgTotal: 2.5, mastersOdds: 400 },
{ participantId: "sp-2", sgTotal: null, usOpenOdds: 800 },
]);
expect(mockDb.insert).toHaveBeenCalledOnce();
expect(mockDb.values).toHaveBeenCalledOnce();
expect(mockDb.onConflictDoUpdate).toHaveBeenCalledOnce();
const passedValues = mockDb.values.mock.calls[0][0] as Array<{
participantId: string;
sgTotal: string | null;
mastersOdds: number | null;
usOpenOdds: number | null;
}>;
expect(passedValues).toHaveLength(2);
expect(passedValues[0].participantId).toBe("canon-1");
expect(passedValues[0].sgTotal).toBe("2.5");
expect(passedValues[0].mastersOdds).toBe(400);
expect(passedValues[1].participantId).toBe("canon-2");
expect(passedValues[1].sgTotal).toBeNull();
expect(passedValues[1].usOpenOdds).toBe(800);
});
it("skips season_participants that have no canonical link", async () => {
mockDb.where.mockResolvedValueOnce([]);
await batchUpsertGolfSkills([
{ participantId: "sp-1", sgTotal: 2.5 },
]);
expect(mockDb.insert).not.toHaveBeenCalled();
});
});