förbättreing tränings

This commit is contained in:
larssand
2026-08-28 21:44:23 +02:00
parent c6262aceab
commit 375bfb2416
14 changed files with 420 additions and 54 deletions

View File

@@ -88,8 +88,8 @@ test("public profile contains only the selected driver's sanitized aggregates",
assert.equal(profile.profile.name, "Driver One");
assert.equal(profile.profile.brand, "Associated 2WD");
assert.equal(profile.profile.className, "2WD");
assert.equal(profile.profile.clubRank, 1);
assert.equal(profile.profile.rankedDrivers, 2);
assert.equal("clubRank" in profile.profile, false);
assert.equal("rankedDrivers" in profile.profile, false);
assert.equal(profile.branding.clubName, "Test Club");
assert.equal(profile.branding.logoDataUrl, "");
assert.equal(profile.stats.totalLaps, 4);

View File

@@ -5,6 +5,7 @@ import {
buildDriverActivePracticeStats,
buildDriverTrainingStats,
buildDriverTimingChannelStats,
buildTrainingAchievements,
buildTrainingRecommendation,
getBestConsecutiveTrainingLaps,
getBestTrainingDurationResult,
@@ -337,3 +338,36 @@ test("goal and automatic milestone progress are bounded", () => {
assert.equal(getNextTrainingMilestone({ totalLaps: 250 }).targetLaps, 500);
assert.equal(getNextTrainingMilestone({ totalLaps: 5200 }).targetLaps, 6000);
});
test("development trend compares the latest 30 laps with the preceding 30", () => {
const start = new Date(2026, 0, 10, 12, 0, 0).getTime();
const ledger = Array.from({ length: 60 }, (_, index) => ({
driverId: "driver_1",
sessionId: "practice_1",
timestamp: start + ((index + 1) * 18_000),
lapMs: index < 30 ? 18_000 : 17_000,
}));
const stats = buildDriverTrainingStats({ training: { ledger } }, "driver_1");
assert.equal(stats.trendSampleReady, true);
assert.equal(stats.previousRecentAverageMs, 18_000);
assert.equal(stats.recentAverageMs, 17_000);
assert.equal(stats.averageTrendMs, 1_000);
assert.equal(stats.consistencyTrendPct, 0);
});
test("automatic achievements expose unlocked and upcoming personal goals", () => {
const achievements = buildTrainingAchievements({
totalSessions: 2,
totalLaps: 520,
trainingDays: 4,
controlledLapStreak: 7,
bestFiveMinuteResult: { lapCount: 17 },
});
assert.equal(achievements.find((item) => item.id === "first_session").unlocked, true);
assert.equal(achievements.find((item) => item.id === "laps_500").unlocked, true);
assert.equal(achievements.find((item) => item.id === "laps_1000").percent, 52);
assert.equal(achievements.find((item) => item.id === "days_10").unlocked, false);
assert.equal(achievements.find((item) => item.id === "five_minute").unlocked, true);
});

View File

@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
import { getDriverProfileGroups } from "../src/driver_profile_logic.js";
import { buildDriverTrainingStats } from "../src/training_logic.js";
import { buildTrainingOverviewRows, resolveTrainingProfile } from "../src/training_views.js";
import { buildTrainingOverviewRows, buildTrainingProgressFeed, resolveTrainingProfile } from "../src/training_views.js";
test("training opens without implicitly selecting the first driver", () => {
const profiles = [{ id: "profile_1", driverIds: ["driver_1"] }];
@@ -33,3 +33,15 @@ test("training overview keeps each driver class on a separate statistics row", (
assert.equal(rows.find((row) => row.classId === "2wd").stats.totalLaps, 2);
assert.equal(rows.find((row) => row.classId === "4wd").stats.totalLaps, 1);
});
test("training progress feed highlights personal development instead of ranking drivers", () => {
const rows = [
{ profile: { id: "p1" }, driver: { name: "Alex" }, classId: "2wd", className: "2WD", stats: { totalLaps: 80, lastLapAt: 200, personalBestGainMs: 250 } },
{ profile: { id: "p2" }, driver: { name: "Kim" }, classId: "4wd", className: "4WD", stats: { totalLaps: 120, lastLapAt: 100, trendSampleReady: true, averageTrendMs: 400 } },
];
const feed = buildTrainingProgressFeed(rows);
assert.deepEqual(feed.map((entry) => entry.profile.id), ["p1", "p2"]);
assert.equal(feed[0].kind, "personal_best");
assert.equal(feed[1].kind, "average_gain");
});