feat(layouts): optional min/max lap time per track layout for practice

Each layout can carry its own lap window (set on creation, editable in
Settings, saved from Race Day during practice). Open/Free practice on
that layout uses it; races always keep the event's values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-10-07 20:33:22 +02:00
parent 8601954ea2
commit 9d79bcb4d3
13 changed files with 174 additions and 15 deletions

View File

@@ -40,6 +40,19 @@ export async function runTrackLayoutsSmoke({ evaluate, navigate, savedState, wai
assert.ok(options.includes((await savedState()).trackLayouts[0].id));
console.log("PASS a track layout can be created from Training stats and the per-layout stats selector appears");
// Settings: the layout gets its own min/max lap time; max <= min is refused.
await navigate("settings", "settingsForm");
const layoutId = (await savedState()).trackLayouts[0].id;
const submitLapWindow = (min, max) => evaluate(`(() => { const form = document.querySelector('[data-layout-lap-window="${layoutId}"]'); form.elements.minLapSec.value = "${min}"; form.elements.maxLapSec.value = "${max}"; form.requestSubmit(); })()`);
await submitLapWindow("8.5", "40");
await waitFor(async () => (await savedState()).trackLayouts[0].minLapMs === 8500, "layout min lap time saved");
assert.equal((await savedState()).trackLayouts[0].maxLapMs, 40000);
const alertsBefore = dialogs.length;
await submitLapWindow("30", "20");
await waitFor(async () => dialogs.slice(alertsBefore).some((dialog) => dialog.type === "alert"), "an impossible lap window is refused");
assert.equal((await savedState()).trackLayouts[0].minLapMs, 8500, "unchanged");
console.log("PASS each track layout can have its own min/max lap time");
await patchState({ activeSessionId: quali.id });
await navigate("race_day", "raceDayStart");
assert.equal(await layoutButtonVisible(), false, "no New layout button while a race session is in focus");