brackt/app/lib/__tests__/corona-states.test.ts
Claude 2d571d8010
Record final-placement points in the score-events ledger
qualifying_points (golf, tennis, CS2) and season_standings (F1) award all
of their points in one step at finalization, so they produce no per-match
deltas. recordMatchScoreEvents is bracket-only and fires from match
processing, which meant these sports were never written to
team_score_events at all and silently never appeared in Recent Scores.

Add recordFinalPlacementScoreEvents, called from finalizeQualifyingPoints
and processSeasonStandings. It writes one row per team at the ledger's
event-level grain, carrying that team's summed award and every
contributing participant, with points from calculatePickPoints so a tied
golfer contributes the same split award the standings show.

The row is anchored to a real scoring event rather than a null one: the
event-level unique index is (teamId, seasonId, scoringEventId) and
Postgres treats NULLs as distinct, so a null anchor would duplicate rows
on every re-finalization instead of upserting. When no anchor can be
resolved the ledger write is skipped, which leaves standings unaffected.

Adds regression coverage for the two screens that had diverged —
getTeamScoreBreakdown and computeCoronaStates — including an assertion
that the team page's actualPoints equals calculateTeamScore's totalPoints
for the same roster, and cases proving undrafted participants still count
toward a tie span.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019LZLF1PAfeKdpYog3NKtyz
2026-08-07 07:38:26 +00:00

122 lines
3.6 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { computeCoronaStates } from "../corona-states";
const RULES = {
pointsFor1st: 100, pointsFor2nd: 70, pointsFor3rd: 50, pointsFor4th: 40,
pointsFor5th: 25, pointsFor6th: 25, pointsFor7th: 15, pointsFor8th: 15,
};
function pick(id: string, scoringPattern: string | null, sportsSeasonId = "ss-1") {
return { participant: { id, sportsSeasonId }, scoringPattern };
}
function results(
rows: Array<{ participantId: string; finalPosition: number | null; isPartialScore?: boolean }>
) {
return new Map(
rows.map((r) => [r.participantId, { isPartialScore: false, ...r }])
);
}
describe("computeCoronaStates", () => {
const noTies = new Map<string, Map<number, number>>();
it("splits points for a tied qualifying_points pick", () => {
// Rahm tied for 8th. 9th is outside the scoring range and contributes 0,
// so (15 + 0) / 2 = 7.5 → 8. Before the shared helper this path awarded the
// full 15 while the standings awarded the split — the reported bug.
const states = computeCoronaStates(
[pick("rahm", "qualifying_points")],
results([{ participantId: "rahm", finalPosition: 8 }]),
new Map(),
RULES,
RULES.pointsFor1st,
new Map([["ss-1", new Map([[8, 2]])]])
);
expect(states.rahm).toEqual({
type: "scored",
points: 8,
brightness: 8 / 100,
});
});
it("awards the full value when the placement is untied", () => {
const states = computeCoronaStates(
[pick("rahm", "qualifying_points")],
results([{ participantId: "rahm", finalPosition: 8 }]),
new Map(),
RULES,
RULES.pointsFor1st,
noTies
);
expect(states.rahm).toMatchObject({ type: "scored", points: 15 });
});
it("still averages bracket tiers via the bracket template", () => {
const states = computeCoronaStates(
[pick("team-a", "playoff_bracket")],
results([{ participantId: "team-a", finalPosition: 5 }]),
new Map([["ss-1", null]]),
RULES,
RULES.pointsFor1st,
noTies
);
// Four QF losers share 5th-8th: (25 + 25 + 15 + 15) / 4 = 20
expect(states["team-a"]).toMatchObject({ type: "scored", points: 20 });
});
it("scores other patterns straight off the placement", () => {
const states = computeCoronaStates(
[pick("driver", "season_standings")],
results([{ participantId: "driver", finalPosition: 2 }]),
new Map(),
RULES,
RULES.pointsFor1st,
noTies
);
expect(states.driver).toMatchObject({ type: "scored", points: 70 });
});
it("marks picks with no result as pending", () => {
const states = computeCoronaStates(
[pick("rahm", "qualifying_points")],
results([]),
new Map(),
RULES,
RULES.pointsFor1st,
noTies
);
expect(states.rahm).toEqual({ type: "pending" });
});
it("marks a finalized zero placement as eliminated", () => {
const states = computeCoronaStates(
[pick("rahm", "qualifying_points")],
results([{ participantId: "rahm", finalPosition: 0 }]),
new Map(),
RULES,
RULES.pointsFor1st,
noTies
);
expect(states.rahm).toEqual({ type: "eliminated", points: 0 });
});
it("keeps brightness within range when a tier exceeds maxPoints", () => {
const states = computeCoronaStates(
[pick("champ", "season_standings")],
results([{ participantId: "champ", finalPosition: 1 }]),
new Map(),
RULES,
10, // deliberately below the 1st-place award
noTies
);
expect(states.champ).toMatchObject({ brightness: 1 });
});
});