feat(training): base training stats on practice, keep race laps separate

Training stats count Open/Free practice by default; laps from
qualifying, heats and finals are kept and shown under Based on: Races
or All, marked with race, session and series. Races are listed per race
session and never split into stints. Same picker in the mobile profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-10-10 20:08:17 +02:00
parent 9a9379aa83
commit af79b610db
15 changed files with 377 additions and 42 deletions

View File

@@ -490,3 +490,20 @@ test("public profile lets the driver pick a layout, an older one, laps from befo
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);
});
test("public profile counts practice by default; race laps only with source race or all", () => {
const now = Date.now();
const state = buildState(now);
state.sessions = [{ id: "free", type: "free_practice" }, { id: "heat_1", type: "heat" }];
state.training.ledger.push(
{ driverId: "driver_1", sessionId: "heat_1", sessionType: "heat", timestamp: now - 9000, lapMs: 15000 },
{ driverId: "driver_1", sessionId: "heat_1", timestamp: now - 7000, lapMs: 15500 }, // type comes from the session
);
const stats = (source) => buildPublicTrainingProfile(state, DRIVER_ONE_TOKEN, "", 0, 0, 0, 0, "current", source).classProfiles.find((item) => item.classId === "class_1").stats;
assert.equal(stats(undefined).totalLaps, 4, "practice only by default");
assert.equal(stats("practice").bestLapMs, 16000);
assert.equal(stats("race").totalLaps, 2);
assert.equal(stats("race").bestLapMs, 15000);
assert.equal(stats("all").totalLaps, 6);
assert.equal(buildPublicTrainingProfile(state, DRIVER_ONE_TOKEN, "", 0, 0, 0, 0, "current", "bogus").lapSource, "practice");
});