fix(lap): keep best laps per track layout and count the current session for records
A layout switch during a running open practice kept every driver's old-layout best lap, blocking personal-best calls and skewing the practice leaderboard. Best laps now restart on a new layout and each lap records its layout. The track record baseline now includes the current session so the same record isn't called twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,12 +48,31 @@ export async function runTrackLayoutsSmoke({ evaluate, navigate, savedState, wai
|
||||
assert.equal(await layoutButtonVisible(), true, "New layout is offered when Open Practice is in focus");
|
||||
console.log("PASS Race Day only offers a new layout when a practice session is in focus");
|
||||
|
||||
// A running open practice moves onto the new layout and its best laps start over, so the
|
||||
// old layout's times can't block or fake a personal best on the rebuilt track.
|
||||
await patchState({
|
||||
sessions: (await savedState()).sessions.map((session) => (session.id === practice.id ? { ...session, status: "running", startedAt: Date.now() - 60000 } : session)),
|
||||
resultsBySession: { ...(await savedState()).resultsBySession, [practice.id]: { passings: [], competitors: { tl_driver: { key: "tl_driver", driverName: "TL Driver", laps: 3, bestLapMs: 18000, bestLapLayoutId: (await savedState()).trackLayouts[0].id } } } },
|
||||
});
|
||||
await navigate("training", "view");
|
||||
await evaluate(`document.querySelector("[data-track-layout-new]").click()`);
|
||||
await waitFor(async () => (await savedState()).trackLayouts?.length === 2, "second layout created");
|
||||
const afterSwitch = await savedState();
|
||||
const newLayoutId = afterSwitch.trackLayouts[1].id;
|
||||
assert.equal(afterSwitch.sessions.find((session) => session.id === practice.id).trackLayoutId, newLayoutId, "the running practice moved onto the new layout");
|
||||
const competitor = afterSwitch.resultsBySession[practice.id].competitors.tl_driver;
|
||||
assert.equal(competitor.bestLapMs, null, "the old layout's best lap no longer counts");
|
||||
assert.equal(competitor.bestLapLayoutId, newLayoutId);
|
||||
assert.equal(competitor.laps, 3, "laps already driven are kept");
|
||||
await patchState({ sessions: (await savedState()).sessions.map((session) => (session.id === practice.id ? { ...session, status: "finished", endedAt: Date.now() } : session)) });
|
||||
console.log("PASS a new layout during open practice restarts every driver's best lap");
|
||||
|
||||
await patchState({ sessions: (await savedState()).sessions.map((session) => (session.id === quali.id ? { ...session, status: "running", startedAt: Date.now() } : session)) });
|
||||
await navigate("training", "view");
|
||||
const dialogCount = dialogs.length;
|
||||
await evaluate(`document.querySelector("[data-track-layout-new]").click()`);
|
||||
await waitFor(async () => dialogs.slice(dialogCount).some((dialog) => dialog.type === "alert" && dialog.message.includes("TL Q1")), "blocked with a message naming the running race");
|
||||
assert.equal((await savedState()).trackLayouts.length, 1, "no layout was added while the race ran");
|
||||
assert.equal((await savedState()).trackLayouts.length, 2, "no layout was added while the race ran");
|
||||
console.log("PASS a new track layout is refused while a race session is running");
|
||||
} finally {
|
||||
dialogs.splice(dialogsAtStart);
|
||||
|
||||
@@ -136,6 +136,27 @@ test("flying start: a car first seen after the latest clock start gets that cloc
|
||||
assert.equal(byDriver("driver_2").lastLapMs, 14_000);
|
||||
});
|
||||
|
||||
test("personal best is per session and track layout - not per stint, and an old layout's time doesn't count", () => {
|
||||
const harness = createHarness({ sessionType: "open_practice" });
|
||||
harness.session.trackLayoutId = "layout_a";
|
||||
const entry = () => Object.values(harness.state.resultsBySession.session_1.competitors)[0];
|
||||
const pbs = () => harness.audioEvents.filter((event) => event === "personal_best").length;
|
||||
harness.passing(21_000, "main"); // 20 s
|
||||
harness.passing(39_000, "main"); // 18 s -> PB
|
||||
assert.equal(pbs(), 1);
|
||||
harness.passing(200_000, "main"); // long break: a new stint, but the 18 s best still stands
|
||||
harness.passing(219_000, "main"); // 19 s - no PB
|
||||
assert.equal(pbs(), 1, "a new stint doesn't reset the personal best");
|
||||
assert.equal(entry().bestLapMs, 18_000);
|
||||
|
||||
harness.session.trackLayoutId = "layout_b"; // the track was rebuilt mid-practice
|
||||
harness.passing(244_000, "main"); // 25 s on the new layout - first lap there, no PB call
|
||||
assert.equal(entry().bestLapMs, 25_000, "the old layout's 18 s no longer counts");
|
||||
harness.passing(268_000, "main"); // 24 s -> PB on the new layout
|
||||
assert.equal(pbs(), 2);
|
||||
assert.equal(harness.state.resultsBySession.session_1.passings.at(-1).trackLayoutId, "layout_b", "each lap remembers its layout");
|
||||
});
|
||||
|
||||
test("pit entry and exit create one timed stop without adding laps", () => {
|
||||
const harness = createHarness();
|
||||
harness.passing(17_000, "main");
|
||||
|
||||
@@ -72,6 +72,20 @@ function createHarness() {
|
||||
};
|
||||
}
|
||||
|
||||
test("recalculating after a judge correction keeps the best lap on the current track layout", () => {
|
||||
const harness = createHarness();
|
||||
harness.session.trackLayoutId = "layout_b";
|
||||
harness.result.passings[0].trackLayoutId = "layout_a"; // the 16.0 s lap was on the old layout
|
||||
harness.result.passings[1].trackLayoutId = "layout_b";
|
||||
harness.result.passings[2].trackLayoutId = "layout_b";
|
||||
harness.deps.recalculateCompetitorFromPassings(harness.session, "driver_1");
|
||||
assert.equal(harness.row.bestLapMs, 16500);
|
||||
assert.equal(harness.row.laps, 3, "laps from the old layout still count as laps");
|
||||
delete harness.result.passings[0].trackLayoutId; // untagged (from before layouts were tagged) still counts
|
||||
harness.deps.recalculateCompetitorFromPassings(harness.session, "driver_1");
|
||||
assert.equal(harness.row.bestLapMs, 16000);
|
||||
});
|
||||
|
||||
test("manual corrections accumulate, reset, and undo to the prior state", () => {
|
||||
const harness = createHarness();
|
||||
|
||||
|
||||
@@ -86,6 +86,21 @@ test("getTrackRecordMs only compares sessions run on the same track layout once
|
||||
assert.equal(getTrackRecordMs(state.sessions[0], { state }), 15000);
|
||||
});
|
||||
|
||||
test("getTrackRecordMs includes the current session, so a record beaten earlier in it is the new bar", () => {
|
||||
const state = createTrackRecordState({
|
||||
sessions: [
|
||||
{ id: "current", eventId: "event_1", trackLayoutId: "layout_1" },
|
||||
{ id: "older", eventId: "event_1", trackLayoutId: "layout_1" },
|
||||
],
|
||||
results: {
|
||||
older: { competitors: { a: { bestLapMs: 16000 } } },
|
||||
current: { competitors: { b: { bestLapMs: 15000 } } },
|
||||
},
|
||||
});
|
||||
// Driver B already set 15.0 here; a 15.5 must not be called a track record again.
|
||||
assert.equal(getTrackRecordMs(state.sessions[0], { state }), 15000);
|
||||
});
|
||||
|
||||
test("getTrackRecordMs does not conflate a layout-tagged session with an untagged legacy one", () => {
|
||||
const state = createTrackRecordState({
|
||||
sessions: [
|
||||
|
||||
Reference in New Issue
Block a user