add more train stats per driver
This commit is contained in:
@@ -6,7 +6,11 @@ import {
|
||||
buildDriverTrainingStats,
|
||||
buildDriverTimingChannelStats,
|
||||
buildTrainingAchievements,
|
||||
buildTrainingMarkerComparisons,
|
||||
buildTrainingPaceBuckets,
|
||||
buildTrainingRecommendation,
|
||||
buildTrainingStintAnalysis,
|
||||
buildTrainingWeekdayStats,
|
||||
getBestConsecutiveTrainingLaps,
|
||||
getBestTrainingDurationResult,
|
||||
getDriverTrainingLaps,
|
||||
@@ -40,6 +44,10 @@ test("normalization removes invalid and duplicate training records", () => {
|
||||
{ driverId: "driver_1", token: "b".repeat(24), enabled: true },
|
||||
{ driverId: "driver_2", token: "short", enabled: true },
|
||||
],
|
||||
markers: [
|
||||
{ id: "marker_1", driverId: "driver_1", classId: "class_1", timestamp: 5000, type: "tires", note: " New tires " },
|
||||
{ id: "marker_invalid", driverId: "", classId: "class_1", timestamp: 5000 },
|
||||
],
|
||||
}, { uid: createUid() });
|
||||
|
||||
assert.equal(normalized.goals.length, 1);
|
||||
@@ -47,6 +55,8 @@ test("normalization removes invalid and duplicate training records", () => {
|
||||
assert.equal(normalized.goals[0].reward, "Badge");
|
||||
assert.deepEqual(normalized.ledger.map((lap) => lap.id), ["lap_1"]);
|
||||
assert.deepEqual(normalized.shares.map((share) => share.token), ["a".repeat(24)]);
|
||||
assert.equal(normalized.markers.length, 1);
|
||||
assert.equal(normalized.markers[0].note, "New tires");
|
||||
});
|
||||
|
||||
test("ledger sync retains archived laps and rebuilds current session laps", () => {
|
||||
@@ -57,6 +67,7 @@ test("ledger sync retains archived laps and rebuilds current session laps", () =
|
||||
{ id: "archived", sourceKey: "old:1", sessionId: "old", driverId: "driver_1", lapMs: 19000, timestamp: 1000 },
|
||||
{ id: "stale", sourceKey: "live:old", sessionId: "live", driverId: "driver_1", lapMs: 30000, timestamp: 2000 },
|
||||
],
|
||||
markers: [{ id: "marker_1", driverId: "driver_1", classId: "class_1", timestamp: 2500, type: "setup" }],
|
||||
};
|
||||
const state = {
|
||||
sessions: [{ id: "live", name: "Free Practice", eventId: "event_1" }],
|
||||
@@ -84,6 +95,7 @@ test("ledger sync retains archived laps and rebuilds current session laps", () =
|
||||
assert.equal(liveLap.eventName, "Club practice");
|
||||
assert.equal(synced.goals.length, 1);
|
||||
assert.equal(synced.shares.length, 1);
|
||||
assert.equal(synced.markers.length, 1);
|
||||
});
|
||||
|
||||
test("driver statistics remain isolated and aggregate days and sessions", () => {
|
||||
@@ -371,3 +383,75 @@ test("automatic achievements expose unlocked and upcoming personal goals", () =>
|
||||
assert.equal(achievements.find((item) => item.id === "days_10").unlocked, false);
|
||||
assert.equal(achievements.find((item) => item.id === "five_minute").unlocked, true);
|
||||
});
|
||||
|
||||
test("pace buckets use a trimmed average and keep classes isolated", () => {
|
||||
const start = new Date(2026, 7, 23, 12, 0, 0).getTime();
|
||||
const twoWheelLaps = [10_000, ...Array.from({ length: 10 }, () => 20_000), 60_000];
|
||||
const state = {
|
||||
drivers: [
|
||||
{ id: "driver_2wd", profileId: "profile", classId: "2wd" },
|
||||
{ id: "driver_4wd", profileId: "profile", classId: "4wd" },
|
||||
],
|
||||
training: {
|
||||
ledger: [
|
||||
...twoWheelLaps.map((lapMs, index) => ({ driverId: "driver_2wd", sessionId: "practice", timestamp: start + index * 60_000, lapMs })),
|
||||
{ driverId: "driver_4wd", sessionId: "practice", timestamp: start + 60_000, lapMs: 14_000 },
|
||||
],
|
||||
markers: [],
|
||||
},
|
||||
};
|
||||
const buckets = buildTrainingPaceBuckets(state, "profile", "2wd", 30);
|
||||
const weekdays = buildTrainingWeekdayStats(state, "profile", "2wd");
|
||||
|
||||
assert.equal(buckets.length, 1);
|
||||
assert.equal(buckets[0].lapCount, 12);
|
||||
assert.equal(buckets[0].paceMs, 20_000);
|
||||
assert.equal(weekdays.find((day) => day.weekday === 0).lapCount, 12);
|
||||
});
|
||||
|
||||
test("setup markers compare only the selected class before and after the change", () => {
|
||||
const markerAt = new Date(2026, 7, 23, 13, 0, 0).getTime();
|
||||
const state = {
|
||||
drivers: [
|
||||
{ id: "driver_2wd", profileId: "profile", classId: "2wd" },
|
||||
{ id: "driver_4wd", profileId: "profile", classId: "4wd" },
|
||||
],
|
||||
training: {
|
||||
ledger: [
|
||||
...[25, 20, 15].map((minutes, index) => ({ driverId: "driver_2wd", timestamp: markerAt - minutes * 60_000, lapMs: 20_000 + index * 100 })),
|
||||
...[5, 10, 15].map((minutes, index) => ({ driverId: "driver_2wd", timestamp: markerAt + minutes * 60_000, lapMs: 18_000 + index * 100 })),
|
||||
{ driverId: "driver_4wd", timestamp: markerAt + 60_000, lapMs: 12_000 },
|
||||
],
|
||||
markers: [{ id: "marker", driverId: "driver_2wd", classId: "2wd", timestamp: markerAt, type: "tires" }],
|
||||
},
|
||||
};
|
||||
const [comparison] = buildTrainingMarkerComparisons(state, "profile", "2wd", 30);
|
||||
|
||||
assert.equal(comparison.beforeLapCount, 3);
|
||||
assert.equal(comparison.afterLapCount, 3);
|
||||
assert.equal(comparison.beforePaceMs, 20_100);
|
||||
assert.equal(comparison.afterPaceMs, 18_100);
|
||||
assert.equal(comparison.improvementMs, 2_000);
|
||||
});
|
||||
|
||||
test("stint analysis hides race pace 10 for short stints and flags slow laps", () => {
|
||||
const firstStart = new Date(2026, 7, 23, 12, 0, 0).getTime();
|
||||
const firstLaps = [...Array.from({ length: 10 }, () => 18_000), 30_000];
|
||||
let timestamp = firstStart;
|
||||
const ledger = firstLaps.map((lapMs) => {
|
||||
timestamp += lapMs;
|
||||
return { driverId: "driver", sessionId: "practice", timestamp, lapMs };
|
||||
});
|
||||
ledger.push({ driverId: "driver", sessionId: "practice", timestamp: timestamp + 180_001, lapMs: 18_000 });
|
||||
ledger.push({ driverId: "driver", sessionId: "practice", timestamp: timestamp + 198_001, lapMs: 18_000 });
|
||||
const analysis = buildTrainingStintAnalysis({ training: { ledger } }, "driver");
|
||||
|
||||
assert.equal(analysis.rows.length, 2);
|
||||
const longStint = analysis.rows.find((row) => row.lapCount === 11);
|
||||
const shortStint = analysis.rows.find((row) => row.lapCount === 2);
|
||||
assert.equal(longStint.racePace10Ms, 18_000);
|
||||
assert.equal(longStint.mistakes, 1);
|
||||
assert.equal(shortStint.racePace10Ms, 0);
|
||||
assert.equal(shortStint.consistencyPct, null);
|
||||
assert.equal(shortStint.insufficient, true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user