publika träningslogik är nu utbruten och testbar
This commit is contained in:
111
tests/public_training_profile.test.js
Normal file
111
tests/public_training_profile.test.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const {
|
||||
buildPublicTrainingProfile,
|
||||
findPublicTrainingShare,
|
||||
hasPublicTrainingShare,
|
||||
normalizePublicTrainingSince,
|
||||
normalizePublicTrainingWindow,
|
||||
} = require("../server/public_training_profile.js");
|
||||
|
||||
const DRIVER_ONE_TOKEN = "driver-one-token-12345678901234567890";
|
||||
const DRIVER_TWO_TOKEN = "driver-two-token-12345678901234567890";
|
||||
const DISABLED_TOKEN = "disabled-token-123456789012345678901";
|
||||
|
||||
function buildState(now = Date.now()) {
|
||||
return {
|
||||
drivers: [
|
||||
{ id: "driver_1", name: "Driver One", brand: "Associated", classId: "class_1", transponder: "secret-transponder-one" },
|
||||
{ id: "driver_2", name: "Driver Two", brand: "Xray", classId: "class_2", transponder: "secret-transponder-two" },
|
||||
],
|
||||
classes: [
|
||||
{ id: "class_1", name: "Modified" },
|
||||
{ id: "class_2", name: "Stock" },
|
||||
],
|
||||
settings: {
|
||||
clubName: "Test Club",
|
||||
clubTagline: "Practice",
|
||||
logoDataUrl: "javascript:alert(1)",
|
||||
wsUrl: "ws://secret-decoder:9000",
|
||||
},
|
||||
training: {
|
||||
shares: [
|
||||
{ driverId: "driver_1", token: DRIVER_ONE_TOKEN, enabled: true },
|
||||
{ driverId: "driver_2", token: DRIVER_TWO_TOKEN, enabled: true },
|
||||
{ driverId: "driver_1", token: DISABLED_TOKEN, enabled: false },
|
||||
],
|
||||
goals: [
|
||||
{ driverId: "driver_1", title: "Bronze", reward: "Badge", targetLaps: 5 },
|
||||
{ driverId: "driver_2", title: "Other goal", reward: "Other reward", targetLaps: 10 },
|
||||
],
|
||||
ledger: [
|
||||
{ driverId: "driver_1", sessionId: "free", timestamp: now - 25 * 60000, lapMs: 19000 },
|
||||
{ driverId: "driver_1", sessionId: "free", timestamp: now - 120000, lapMs: 18000 },
|
||||
{ driverId: "driver_1", sessionId: "free", timestamp: now - 12000, lapMs: 16500 },
|
||||
{ driverId: "driver_1", sessionId: "free", timestamp: now - 4000, lapMs: 16000 },
|
||||
{ driverId: "driver_1", sessionId: "free", timestamp: now - 2000, lapMs: 500 },
|
||||
{ driverId: "driver_2", sessionId: "free", timestamp: now - 3000, lapMs: 12000 },
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test("public share lookup rejects short, disabled, and unknown tokens", () => {
|
||||
const state = buildState();
|
||||
assert.equal(findPublicTrainingShare(state, "short"), null);
|
||||
assert.equal(findPublicTrainingShare(state, DISABLED_TOKEN), null);
|
||||
assert.equal(hasPublicTrainingShare(state, "unknown-token-123456789012345678"), false);
|
||||
assert.equal(hasPublicTrainingShare(state, DRIVER_ONE_TOKEN), true);
|
||||
});
|
||||
|
||||
test("public profile contains only the selected driver's sanitized aggregates", () => {
|
||||
const now = Date.now();
|
||||
const profile = buildPublicTrainingProfile(buildState(now), DRIVER_ONE_TOKEN, "2026-08-24T12:00:00.000Z", now - 30000, 30000);
|
||||
|
||||
assert.equal(profile.profile.name, "Driver One");
|
||||
assert.equal(profile.profile.brand, "Associated");
|
||||
assert.equal(profile.profile.className, "Modified");
|
||||
assert.equal(profile.profile.clubRank, 1);
|
||||
assert.equal(profile.profile.rankedDrivers, 2);
|
||||
assert.equal(profile.branding.clubName, "Test Club");
|
||||
assert.equal(profile.branding.logoDataUrl, "");
|
||||
assert.equal(profile.stats.totalLaps, 4);
|
||||
assert.equal(profile.stats.bestLapMs, 16000);
|
||||
assert.deepEqual(profile.currentSession, { laps: 2, bestLapMs: 16000, averageLapMs: 16250 });
|
||||
assert.equal(profile.goals.length, 1);
|
||||
assert.equal(profile.goals[0].title, "Bronze");
|
||||
assert.equal(profile.goals[0].percent, 80);
|
||||
|
||||
const serialized = JSON.stringify(profile);
|
||||
assert.equal(serialized.includes("Driver Two"), false);
|
||||
assert.equal(serialized.includes("driver_1"), false);
|
||||
assert.equal(serialized.includes("secret-transponder"), false);
|
||||
assert.equal(serialized.includes("secret-decoder"), false);
|
||||
});
|
||||
|
||||
test("public timer window freezes aggregates after the personal session", () => {
|
||||
const now = Date.now();
|
||||
const profile = buildPublicTrainingProfile(buildState(now), DRIVER_ONE_TOKEN, "", now - 30 * 60000, 20 * 60000);
|
||||
|
||||
assert.deepEqual(profile.currentSession, { laps: 1, bestLapMs: 19000, averageLapMs: 19000 });
|
||||
});
|
||||
|
||||
test("public profile returns null when token or driver is unavailable", () => {
|
||||
const state = buildState();
|
||||
assert.equal(buildPublicTrainingProfile(state, DISABLED_TOKEN, ""), null);
|
||||
state.drivers = state.drivers.filter((driver) => driver.id !== "driver_1");
|
||||
assert.equal(buildPublicTrainingProfile(state, DRIVER_ONE_TOKEN, ""), null);
|
||||
});
|
||||
|
||||
test("public timer query normalization bounds age and window values", () => {
|
||||
const before = Date.now();
|
||||
const since = normalizePublicTrainingSince(undefined, "30000");
|
||||
const after = Date.now();
|
||||
assert.ok(since >= before - 30000 && since <= after - 30000);
|
||||
assert.equal(normalizePublicTrainingSince(undefined, String(25 * 60 * 60 * 1000)), 0);
|
||||
assert.equal(normalizePublicTrainingWindow("-100"), 0);
|
||||
assert.equal(normalizePublicTrainingWindow(String(25 * 60 * 60 * 1000)), 24 * 60 * 60 * 1000);
|
||||
});
|
||||
Reference in New Issue
Block a user