diff --git a/app/models/__tests__/surface-elo.test.ts b/app/models/__tests__/surface-elo.test.ts index 307a87a..017543b 100644 --- a/app/models/__tests__/surface-elo.test.ts +++ b/app/models/__tests__/surface-elo.test.ts @@ -42,10 +42,10 @@ describe("getSurfaceEloMap", () => { expect(result.size).toBe(0); }); - it("returns a Map keyed by participantId", async () => { + it("returns a Map keyed by seasonParticipantId", async () => { mockDb.where.mockResolvedValue([ - { participantId: "p1", worldRanking: 1, eloHard: 1800, eloClay: 1700, eloGrass: 1600 }, - { participantId: "p2", worldRanking: null, eloHard: null, eloClay: 1750, eloGrass: null }, + { seasonParticipantId: "p1", worldRanking: 1, eloHard: 1800, eloClay: 1700, eloGrass: 1600 }, + { seasonParticipantId: "p2", worldRanking: null, eloHard: null, eloClay: 1750, eloGrass: null }, ]); const result = await getSurfaceEloMap("season-1"); expect(result.size).toBe(2); @@ -55,7 +55,7 @@ describe("getSurfaceEloMap", () => { it("preserves null surface Elos (does not coerce to 0)", async () => { mockDb.where.mockResolvedValue([ - { participantId: "p1", worldRanking: null, eloHard: null, eloClay: null, eloGrass: null }, + { seasonParticipantId: "p1", worldRanking: null, eloHard: null, eloClay: null, eloGrass: null }, ]); const result = await getSurfaceEloMap("season-1"); const entry = result.get("p1"); @@ -72,7 +72,13 @@ describe("batchUpsertSurfaceElos", () => { expect(mockDb.insert).not.toHaveBeenCalled(); }); - it("calls insert with the correct values", async () => { + it("calls insert with the correct values on the per-window table", async () => { + // The function first upserts to the per-window table, then reads + // season_participants for canonical-id lookup. Make the follow-up select + // return empty so the canonical write path short-circuits and we only + // observe the per-window insert in this assertion. + mockDb.where.mockResolvedValue([]); + const inputs = [ { participantId: "p1", sportsSeasonId: "s1", worldRanking: 1, eloHard: 1800, eloClay: 1700, eloGrass: 1600 }, { participantId: "p2", sportsSeasonId: "s1", worldRanking: null, eloHard: null, eloClay: 1750, eloGrass: undefined }, @@ -95,11 +101,36 @@ describe("batchUpsertSurfaceElos", () => { }); it("uses onConflictDoUpdate for upsert behaviour", async () => { + mockDb.where.mockResolvedValue([]); // no canonical links; only per-window write + await batchUpsertSurfaceElos([ { participantId: "p1", sportsSeasonId: "s1", worldRanking: 5, eloHard: 2000 }, ]); expect(mockDb.onConflictDoUpdate).toHaveBeenCalledOnce(); }); + + it("mirrors writes to canonical participant_surface_elos when linked", async () => { + // season_participants lookup returns canonical links for p1 only. + mockDb.where.mockResolvedValue([ + { id: "p1", canonicalId: "canon-1" }, + ]); + + await batchUpsertSurfaceElos([ + { participantId: "p1", sportsSeasonId: "s1", worldRanking: 5, eloHard: 2000 }, + ]); + + // One per-window insert, one canonical insert → two inserts total. + expect(mockDb.insert).toHaveBeenCalledTimes(2); + expect(mockDb.onConflictDoUpdate).toHaveBeenCalledTimes(2); + + const canonicalValues = mockDb.values.mock.calls[1][0] as Array<{ + participantId: string; + eloHard: number | null; + }>; + expect(canonicalValues).toHaveLength(1); + expect(canonicalValues[0].participantId).toBe("canon-1"); + expect(canonicalValues[0].eloHard).toBe(2000); + }); }); describe("getSurfaceElosForSeason", () => {