Add moving a driver between qualifying heats
The user asked whether a lone driver left in the last heat (e.g. 7
drivers at 3 per heat) could be moved into another heat manually.
Investigated first: neither "Reseed" (redistributes every not-yet-run
heat by current standings, not a targeted move) nor the grid editor
(reorders start position within one heat, never moves a driver
between heats) could do this - there was genuinely no path to it.
moveDriversIntoQualifyingHeat (src/event_race_logic.js) adds the same
"checking them elsewhere is the move" pattern already used for team
rosters: a new driver checklist on the qualification session edit
form pulls a checked driver out of whichever other heat they're
currently on, scoped to the same round only ("Q2 H2" never touches
"Q1"/"Q3", since heat composition can legitimately differ round to
round after a reseed). The checklist names the driver's current heat
before saving, mirroring the team-roster warning.
Also confirmed, per the user's earlier questions, already correct
with no changes needed: practice's per-driver "best 3 laps"/"best
5-minute result" stats, and that heats are already seeded fastest-
first from practice results. Flagged one real, deliberately unbuilt
gap while investigating: a true per-driver rolling "5 minutes from
your own first crossing" qualifying *heat* clock isn't supported -
only the practice stats work that way today.
Verified with new unit tests for moveDriversIntoQualifyingHeat and
the extracted parseQualifyingHeatName helper, and a real headless-
browser run reproducing the exact reported scenario end to end
through the actual UI.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,9 @@ import {
|
||||
generateFinalsForRace,
|
||||
generateQualifyingForRace,
|
||||
getTeamDriverPool,
|
||||
moveDriversIntoQualifyingHeat,
|
||||
normalizeEvent,
|
||||
parseQualifyingHeatName,
|
||||
reassignTeamMembers,
|
||||
reseedUpcomingQualifying,
|
||||
} from "../src/event_race_logic.js";
|
||||
@@ -330,6 +332,38 @@ test("qualifying reseed reports a field-size mismatch instead of silently droppi
|
||||
assert.equal(result.mismatched, 1, "the round's ready-heat count no longer matches the participant list");
|
||||
});
|
||||
|
||||
test("parseQualifyingHeatName extracts the round and heat number, or null for anything else", () => {
|
||||
assert.deepEqual(parseQualifyingHeatName("Q2 H3"), { round: 2, heat: 3 });
|
||||
assert.deepEqual(parseQualifyingHeatName("Q10 H11"), { round: 10, heat: 11 });
|
||||
assert.equal(parseQualifyingHeatName("A Final 1"), null);
|
||||
assert.equal(parseQualifyingHeatName(""), null);
|
||||
});
|
||||
|
||||
test("moveDriversIntoQualifyingHeat moves a lone driver out of their old heat into a new one, in the same round only", () => {
|
||||
const sessions = [
|
||||
{ id: "q1h1", name: "Q1 H1", type: "qualification", driverIds: ["d1", "d2"], manualGridIds: ["d1", "d2"] },
|
||||
{ id: "q1h2", name: "Q1 H2", type: "qualification", driverIds: ["d3"], manualGridIds: ["d3"] },
|
||||
// A different round's H1 must never be touched by an edit to Q1's heats.
|
||||
{ id: "q2h1", name: "Q2 H1", type: "qualification", driverIds: ["d1", "d2"], manualGridIds: ["d1", "d2"] },
|
||||
];
|
||||
moveDriversIntoQualifyingHeat(sessions, "q1h1", ["d1", "d2", "d3"]);
|
||||
|
||||
const q1h1 = sessions.find((s) => s.id === "q1h1");
|
||||
const q1h2 = sessions.find((s) => s.id === "q1h2");
|
||||
const q2h1 = sessions.find((s) => s.id === "q2h1");
|
||||
assert.deepEqual(q1h2.driverIds, [], "d3 was pulled out of Q1 H2, the heat they were lonely in");
|
||||
assert.deepEqual(q2h1.driverIds, ["d1", "d2"], "Q2's heats are untouched - only Q1's heats are affected by editing a Q1 heat");
|
||||
// moveDriversIntoQualifyingHeat only clears the OTHER sessions - the caller (the real
|
||||
// sessionEditForm handler) is the one that sets the target session's own driverIds.
|
||||
assert.equal(q1h1.id, "q1h1");
|
||||
});
|
||||
|
||||
test("moveDriversIntoQualifyingHeat does nothing for a session with no parseable heat name", () => {
|
||||
const sessions = [{ id: "s1", name: "Open Practice", type: "practice", driverIds: ["d1"] }];
|
||||
moveDriversIntoQualifyingHeat(sessions, "s1", ["d1"]);
|
||||
assert.deepEqual(sessions[0].driverIds, ["d1"], "left untouched - not a qualifying heat, nothing to move");
|
||||
});
|
||||
|
||||
test("final generation reserves bump slots and keeps seeded grid order", () => {
|
||||
const state = { sessions: [] };
|
||||
const sourceRows = Array.from({ length: 7 }, (_, index) => ({ driverId: `driver_${index + 1}` }));
|
||||
|
||||
Reference in New Issue
Block a user