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:
@@ -8,7 +8,9 @@ import {
|
||||
buildRaceSessionsFromWizard,
|
||||
generateFinalsForRace,
|
||||
generateQualifyingForRace,
|
||||
getTeamDriverPool,
|
||||
normalizeEvent,
|
||||
reassignTeamMembers,
|
||||
reseedUpcomingQualifying,
|
||||
} from "../src/event_race_logic.js";
|
||||
import {
|
||||
@@ -135,6 +137,43 @@ test("event normalization preserves the practice-only marker", () => {
|
||||
assert.equal(event.raceConfig.presetId, "custom");
|
||||
});
|
||||
|
||||
test("reassignTeamMembers strips a moved driver/car from every other team, leaving the excluded team untouched", () => {
|
||||
const teams = [
|
||||
{ id: "team_a", name: "A", driverIds: ["d1", "d2"], carIds: ["c1"] },
|
||||
{ id: "team_b", name: "B", driverIds: ["d3"], carIds: [] },
|
||||
];
|
||||
const result = reassignTeamMembers(teams, { excludeTeamId: "team_b", driverIds: ["d1"], carIds: ["c1"] });
|
||||
const teamA = result.find((team) => team.id === "team_a");
|
||||
const teamB = result.find((team) => team.id === "team_b");
|
||||
assert.deepEqual(teamA.driverIds, ["d2"], "d1 was moved out of team A");
|
||||
assert.deepEqual(teamA.carIds, [], "c1 was moved out of team A too");
|
||||
assert.deepEqual(teamB.driverIds, ["d3"], "the team being saved is left for the caller to update, not touched here");
|
||||
});
|
||||
|
||||
test("reassignTeamMembers returns unchanged team objects as-is when nothing overlaps", () => {
|
||||
const teams = [{ id: "team_a", name: "A", driverIds: ["d1"], carIds: [] }];
|
||||
const result = reassignTeamMembers(teams, { excludeTeamId: "team_b", driverIds: ["d9"], carIds: [] });
|
||||
assert.strictEqual(result[0], teams[0]);
|
||||
});
|
||||
|
||||
test("getTeamDriverPool scopes to the event's class/participants, only falling back to every driver when that list is empty", () => {
|
||||
const state = {
|
||||
drivers: [
|
||||
{ id: "d1", name: "One", classId: "2wd" },
|
||||
{ id: "d2", name: "Two", classId: "4wd" },
|
||||
],
|
||||
};
|
||||
const getEventDrivers = (event) => state.drivers.filter((driver) => !event?.classId || driver.classId === event.classId);
|
||||
|
||||
const scoped = getTeamDriverPool({ classId: "2wd", raceConfig: {} }, { getEventDrivers, state });
|
||||
assert.deepEqual(scoped.drivers.map((driver) => driver.id), ["d1"]);
|
||||
assert.equal(scoped.fallback, false);
|
||||
|
||||
const noMatches = getTeamDriverPool({ classId: "unknown_class", raceConfig: {} }, { getEventDrivers, state });
|
||||
assert.deepEqual(noMatches.drivers.map((driver) => driver.id), ["d1", "d2"], "falls back to every driver rather than leaving zero checkboxes");
|
||||
assert.equal(noMatches.fallback, true);
|
||||
});
|
||||
|
||||
test("race wizard creates configured practice, qualifying, and endurance sessions", () => {
|
||||
const event = {
|
||||
id: "event_1",
|
||||
|
||||
Reference in New Issue
Block a user