feat(layouts): switch track layout mid-practice and view stats per layout
A club can run one Open Practice all season and re-lay the track now and then. Previously a session's layout was frozen at start and every training lap inherited it, so a season-long practice stayed on its first layout forever, and changing layout was hidden under Settings -> Appearance. - Each practice lap now counts toward the layout active when it was driven; a running practice session moves onto a new layout when one is added - "New layout" strip on Training stats, Race Day and the Dashboard, offered only around practice; a running race session blocks layout changes everywhere - "Stats for" selector (current / older layout / before layouts / all layouts) on Training stats and in the driver's mobile profile (?layout= on the public API) - A layout that has practice laps on it can no longer be deleted - Fix: the buildDriverTrainingStats wrapper in app.js dropped extra arguments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -464,3 +464,29 @@ test("a goal targeting completed sessions computes progress from real exerciseSe
|
||||
assert.ok(!serialized.includes("driver_1"), "exercise session history must never expose driverId");
|
||||
assert.ok(!serialized.includes("class_1"), "exercise session history must never expose classId");
|
||||
});
|
||||
|
||||
test("public profile lets the driver pick a layout, an older one, laps from before layouts, or all of them", () => {
|
||||
const now = Date.now();
|
||||
const oldLayoutDay = now - 60 * 24 * 60 * 60 * 1000;
|
||||
const state = buildState(now);
|
||||
state.trackLayouts = [
|
||||
{ id: "layout_2", label: "Layout 2", startedAt: now - 24 * 60 * 60 * 1000 },
|
||||
{ id: "layout_1", label: "Layout 1", startedAt: oldLayoutDay - 1000 },
|
||||
];
|
||||
state.training.ledger.push(
|
||||
{ driverId: "driver_1", sessionId: "old_track", timestamp: oldLayoutDay, lapMs: 9000, trackLayoutId: "layout_1" },
|
||||
{ driverId: "driver_1", sessionId: "old_track", timestamp: oldLayoutDay + 10000, lapMs: 9200, trackLayoutId: "layout_1" },
|
||||
);
|
||||
const best = (layout) => buildPublicTrainingProfile(state, DRIVER_ONE_TOKEN, "", 0, 0, 0, 0, layout).classProfiles.find((item) => item.classId === "class_1").stats.bestLapMs;
|
||||
assert.equal(best("layout_1"), 9000, "an older layout");
|
||||
assert.equal(best("all"), 9000, "all layouts = overall best");
|
||||
assert.ok(best("none") > 9000, "laps from before any layout existed, without the layout_1 laps");
|
||||
assert.equal(best("current"), 0, "nothing driven on the current layout yet");
|
||||
assert.equal(best("layout_that_does_not_exist"), 0, "an unknown choice falls back to the current layout");
|
||||
|
||||
const layouts = buildPublicTrainingProfile(state, DRIVER_ONE_TOKEN, "", 0, 0, 0, 0, "all").trackLayouts;
|
||||
assert.equal(layouts.selected, "all");
|
||||
assert.equal(layouts.currentId, "layout_2");
|
||||
assert.deepEqual(layouts.options, [{ id: "layout_1", label: "Layout 1" }, { id: "layout_2", label: "Layout 2" }], "oldest first, only id and label are exposed");
|
||||
assert.equal(layouts.hasUntaggedLaps, true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user