solverforge-deliveries / tests /frontend_models.test.mjs
blackopsrepl's picture
fix(ui): highlight delivery routes by vehicle identity
a6c5209
import test from 'node:test';
import assert from 'node:assert/strict';
import {
buildDeliveryTimelineModel,
buildVehicleTimelineModel,
refreshPlan,
refreshServerPlan,
} from '../static/app/models.mjs';
import {
colorForVehicle,
routeStyleForVehicle,
} from '../static/app/ui/overview.mjs';
function basePlan() {
return {
name: 'Test City',
routingMode: 'straight_line',
deliveries: [
{
id: 0,
label: 'A',
kind: 'business',
lat: 43.7696,
lng: 11.2558,
demand: 3,
minStartTime: 8 * 3600,
maxEndTime: 12 * 3600,
serviceDuration: 10 * 60,
},
{
id: 1,
label: 'B',
kind: 'residential',
lat: 43.7710,
lng: 11.2620,
demand: 2,
minStartTime: 9 * 3600,
maxEndTime: 18 * 3600,
serviceDuration: 5 * 60,
},
],
vehicles: [
{
id: 0,
name: 'Alpha',
capacity: 10,
homeLat: 43.7696,
homeLng: 11.2558,
departureTime: 6 * 3600,
deliveryOrder: [0, 1],
},
],
viewState: {},
};
}
test('refreshPlan builds preview assignments and scores', () => {
const plan = refreshPlan(basePlan());
assert.equal(plan.viewState.preview.vehicles.length, 1);
assert.equal(plan.viewState.preview.deliveries[0].assignedVehicleName, 'Alpha');
assert.equal(plan.viewState.preview.unassignedDeliveryIds.length, 0);
});
test('refreshServerPlan preserves authoritative backend preview', () => {
const plan = basePlan();
plan.viewState.preview = {
hardScore: -99,
softScore: -12345,
unassignedDeliveryIds: [1],
vehicles: [],
deliveries: [],
};
const refreshed = refreshServerPlan(plan);
assert.equal(refreshed.viewState.preview.hardScore, -99);
assert.equal(refreshed.viewState.preview.softScore, -12345);
assert.deepEqual(refreshed.viewState.preview.unassignedDeliveryIds, [1]);
});
test('refreshPlan recomputes draft preview from straight-line estimates', () => {
const plan = basePlan();
plan.viewState.preview = {
hardScore: -99,
softScore: -12345,
unassignedDeliveryIds: [1],
vehicles: [],
deliveries: [],
};
const refreshed = refreshPlan(plan);
assert.equal(Math.abs(refreshed.viewState.preview.hardScore), 0);
assert.notEqual(refreshed.viewState.preview.softScore, -12345);
assert.equal(refreshed.viewState.preview.vehicles.length, 1);
assert.ok(refreshed.viewState.preview.vehicles[0].totalTravelSeconds > 0);
});
test('refreshPlan uses dominant unassigned-delivery hard penalty', () => {
const plan = basePlan();
plan.vehicles[0].deliveryOrder = [0];
const refreshed = refreshPlan(plan);
assert.equal(refreshed.viewState.preview.unassignedDeliveryIds.length, 1);
assert.ok(
refreshed.viewState.preview.hardScore <= -1_000_000,
`expected unassigned hard penalty to dominate, got ${refreshed.viewState.preview.hardScore}`,
);
});
test('timeline model builders emit lane collections', () => {
const preview = refreshPlan(basePlan()).viewState.preview;
const vehicleModel = buildVehicleTimelineModel(preview);
const deliveryModel = buildDeliveryTimelineModel(preview);
assert.equal(vehicleModel.lanes.length, 1);
assert.equal(vehicleModel.lanes[0].items.length, 2);
assert.equal(deliveryModel.lanes.length, 2);
assert.ok(deliveryModel.lanes[0].items.length >= 1);
});
test('vehicle map colors are unique across the ten-vehicle tutorial dataset', () => {
const colors = Array.from({ length: 10 }, (_, vehicleId) => colorForVehicle(vehicleId));
assert.equal(new Set(colors).size, 10);
assert.notEqual(colorForVehicle(1), colorForVehicle(9));
});
test('route highlight style is keyed by vehicle id, not color reuse', () => {
assert.deepEqual(routeStyleForVehicle(1, 1), {
color: colorForVehicle(1),
opacity: 1,
weight: 5,
});
assert.deepEqual(routeStyleForVehicle(9, 1), {
color: colorForVehicle(9),
opacity: 0.2,
weight: 2,
});
});