import assert from "node:assert/strict"; import test from "node:test"; import { formatCotacol, formatSpeed, groupRidePoints, groupedPoints, niceStep, ticks, type ColorBy } from "./analytics-logic.ts"; import type { AnalyticsPoint } from "./types.js"; const makePoint = (overrides: Partial>): AnalyticsPoint => ({ id: 1, name: "ride", url: "/rides/1", speedKmh: 20, cotacolPer100Km: 50, movingHours: 2, year: 2020, rideType: "", bikeType: "", ...overrides, }); test("computes a pleasant axis step within a 1-2-5-10 series", () => { assert.equal(niceStep(25, 5), 5); assert.equal(niceStep(60, 5), 10); assert.equal(niceStep(3.6, 5), 0.5); assert.equal(niceStep(0, 5), 1); }); test("produces ascending ticks that bracket the data range and include its max", () => { assert.deepEqual(ticks(0, 27.9), [0, 5, 10, 15, 20, 25]); assert.deepEqual(ticks(0, 315), [0, 50, 100, 150, 200, 250, 300]); const values = ticks(0, 27.9); for (let index = 1; index < values.length; index++) { assert.ok(values[index] > values[index - 1]); } assert.ok(values[values.length - 1] <= 27.9 + 1e-9); }); test("formats speed and cotacol per 100 km for axis labels", () => { assert.equal(formatSpeed(25.2), "25.2"); assert.equal(formatCotacol(300), "300"); assert.equal(formatCotacol(50), "50.0"); }); test("grouping by none produces no legend groups", () => { assert.deepEqual(groupRidePoints([makePoint({})], "none"), []); }); test("groups by year ascending with compact color indices", () => { const points = [makePoint({ year: 2021 }), makePoint({ year: 2020 }), makePoint({ year: 2021 })]; assert.deepEqual(groupRidePoints(points, "year"), [ { label: "2020", count: 1, colorIndex: 0 }, { label: "2021", count: 2, colorIndex: 1 }, ]); assert.deepEqual( groupedPoints(points, "year").map(({ point, colorIndex }) => [point.year, colorIndex]), [ [2021, 1], [2020, 0], [2021, 1], ], ); }); test("groups by ride type in stable order with stable color indices", () => { const points = [makePoint({ rideType: "race" }), makePoint({ rideType: "training" }), makePoint({ rideType: "race" })]; assert.deepEqual(groupRidePoints(points, "rideType"), [ { label: "Training", count: 1, colorIndex: 0 }, { label: "Race", count: 2, colorIndex: 2 }, ]); }); test("empty ride and bike types land in an Unknown group", () => { const points = [makePoint({ rideType: "" }), makePoint({ rideType: "race" })]; assert.deepEqual(groupRidePoints(points, "rideType"), [ { label: "Race", count: 1, colorIndex: 2 }, { label: "Unknown", count: 1, colorIndex: 5 }, ]); const bikes = [makePoint({ bikeType: "" }), makePoint({ bikeType: "road" })]; assert.deepEqual(groupRidePoints(bikes, "bikeType"), [ { label: "Road", count: 1, colorIndex: 0 }, { label: "Unknown", count: 1, colorIndex: 2 }, ]); }); test("color by mode is limited to the supported dimensions", () => { const modes: ColorBy[] = ["none", "year", "rideType", "bikeType"]; assert.deepEqual(modes, ["none", "year", "rideType", "bikeType"]); });