Fix Team Race duplicate-membership bug and two related team-roster gaps
Reported by the user: creating a team, adding the wrong driver, then moving that driver to another team by ticking them on the new team's edit form left the driver on both teams at once. Root cause: there was never a "move" action - the edit form only ever added a driver to the team being saved, never removed them from wherever they already were. Live laps from a driver on two teams were then silently credited to only the first-matching team, with no clear error. reassignTeamMembers (event_race_logic.js) now strips a driver/car being saved onto one team out of every other team in the same event, and the team checkbox list shows which team a driver is already on before you move them. Also fixed two related gaps found while investigating, at the user's request to fix everything: getTeamDriverPool had regressed to ignoring the event's class/participant scoping entirely (showing every driver in the club), and deleting a driver or car left them behind in team rosters forever. Added a duplicate_team_members Race Day preflight check as defense in depth for any already-corrupted saved state. Verified with new unit tests for reassignTeamMembers, getTeamDriverPool and the new preflight check, plus a new permanent browser test reproducing the user's exact reported scenario end to end. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,31 @@ test("open practice allows an unset lap window but still requires the main decod
|
||||
assert.equal(result.ready, false);
|
||||
});
|
||||
|
||||
test("team_race preflight blocks a driver saved onto two teams at once, naming them instead of a generic transponder error", () => {
|
||||
const state = createState();
|
||||
state.sessions.push({ id: "session_team", eventId: "event_1", name: "Team Race", mode: "race", type: "team_race", status: "ready", startMode: "mass" });
|
||||
state.events[0].raceConfig.teams = [
|
||||
{ id: "team_a", name: "Team A", driverIds: ["driver_1"], carIds: [] },
|
||||
{ id: "team_b", name: "Team B", driverIds: ["driver_1", "driver_2"], carIds: [] },
|
||||
];
|
||||
const result = buildRaceDayPreflight(state, state.sessions.find((s) => s.id === "session_team"), { backendAvailable: true });
|
||||
assert.equal(result.ready, false);
|
||||
const duplicateCheck = result.checks.find((item) => item.id === "duplicate_team_members");
|
||||
assert.equal(duplicateCheck.level, "error");
|
||||
assert.deepEqual(duplicateCheck.duplicateTeamMemberNames, ["One"]);
|
||||
});
|
||||
|
||||
test("team_race preflight accepts teams with no members in common", () => {
|
||||
const state = createState();
|
||||
state.sessions.push({ id: "session_team", eventId: "event_1", name: "Team Race", mode: "race", type: "team_race", status: "ready", startMode: "mass" });
|
||||
state.events[0].raceConfig.teams = [
|
||||
{ id: "team_a", name: "Team A", driverIds: ["driver_1"], carIds: [] },
|
||||
{ id: "team_b", name: "Team B", driverIds: ["driver_2"], carIds: [] },
|
||||
];
|
||||
const result = buildRaceDayPreflight(state, state.sessions.find((s) => s.id === "session_team"), { backendAvailable: true });
|
||||
assert.equal(result.checks.find((item) => item.id === "duplicate_team_members").level, "ok");
|
||||
});
|
||||
|
||||
test("preflight presents blockers before warnings without changing the original checks", async () => {
|
||||
const { sortRaceDayChecks } = await import("../src/race_day_view.js");
|
||||
const checks = [{ id: "audio", level: "warning" }, { id: "session", level: "ok" }, { id: "decoder", level: "error" }];
|
||||
|
||||
Reference in New Issue
Block a user