brackt/app/models/__tests__/canonical-golf-skills.test.ts
Chris Parsons 21dfe3627c
Canonical golf skills migration + copy participants feature (#369)
Migrate participant_golf_skills from per-season to canonical table (one
row per real-world player), mirroring the existing participant_surface_elos
pattern. Adds admin UI to copy participants between same-sport seasons with
EV stubs, transactional writes, and comprehensive tests.
2026-05-02 10:29:28 -07:00

105 lines
2.7 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("~/database/context", () => ({
database: vi.fn(),
}));
import {
upsertCanonicalGolfSkills,
getCanonicalGolfSkills,
} from "../canonical-golf-skills";
import { database } from "~/database/context";
const PARTICIPANT_ID = "participant-1";
const SAMPLE_SKILLS = {
id: "skill-1",
participantId: PARTICIPANT_ID,
sgTotal: "2.50",
datagolfRank: 3,
mastersOdds: 800,
usOpenOdds: 1200,
openChampionshipOdds: 1000,
pgaChampionshipOdds: 900,
updatedAt: new Date("2026-01-28T00:00:00Z"),
};
function makeUpsertDb(returnValue: object) {
return {
insert: vi.fn().mockReturnValue({
values: vi.fn().mockReturnValue({
onConflictDoUpdate: vi.fn().mockReturnValue({
returning: vi.fn().mockResolvedValue([returnValue]),
}),
}),
}),
};
}
function makeSelectDb(rows: object[]) {
return {
query: {
participantGolfSkills: {
findFirst: vi.fn().mockResolvedValue(rows[0] ?? null),
},
},
};
}
beforeEach(() => {
vi.clearAllMocks();
});
describe("upsertCanonicalGolfSkills", () => {
it("inserts or updates golf skill data", async () => {
vi.mocked(database).mockReturnValue(makeUpsertDb(SAMPLE_SKILLS) as never);
const result = await upsertCanonicalGolfSkills({
participantId: PARTICIPANT_ID,
sgTotal: "2.50",
datagolfRank: 3,
mastersOdds: 800,
});
expect(result).toEqual(SAMPLE_SKILLS);
});
it("throws if participantId is missing", async () => {
await expect(
upsertCanonicalGolfSkills({ participantId: undefined as unknown as string }),
).rejects.toThrow("participantId is required");
});
it("uses onConflictDoUpdate on participantId", async () => {
const mockDb = makeUpsertDb(SAMPLE_SKILLS);
vi.mocked(database).mockReturnValue(mockDb as never);
await upsertCanonicalGolfSkills({
participantId: PARTICIPANT_ID,
sgTotal: "2.50",
});
const onConflictCall = (mockDb.insert as ReturnType<typeof vi.fn>)
.mock.results[0].value.values.mock.results[0].value.onConflictDoUpdate;
expect(onConflictCall).toHaveBeenCalled();
});
});
describe("getCanonicalGolfSkills", () => {
it("returns skills when found", async () => {
vi.mocked(database).mockReturnValue(makeSelectDb([SAMPLE_SKILLS]) as never);
const result = await getCanonicalGolfSkills(PARTICIPANT_ID);
expect(result).toEqual(SAMPLE_SKILLS);
});
it("returns null when not found", async () => {
vi.mocked(database).mockReturnValue(makeSelectDb([]) as never);
const result = await getCanonicalGolfSkills("nonexistent");
expect(result).toBeNull();
});
});