From 0697fd13cd67cbe13185019c3884510d07ab9cf9 Mon Sep 17 00:00:00 2001 From: visha raut Date: Mon, 8 Jun 2026 23:18:25 +0530 Subject: [PATCH 1/4] fix: add null safeguard and source-asymmetry test for buildVehiclePopupData --- src/lib/__tests__/vehicleUtils.test.js | 44 ++++++++++++++++++++++++++ src/lib/vehicleUtils.js | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/lib/__tests__/vehicleUtils.test.js b/src/lib/__tests__/vehicleUtils.test.js index c20f32a7..41d46240 100644 --- a/src/lib/__tests__/vehicleUtils.test.js +++ b/src/lib/__tests__/vehicleUtils.test.js @@ -48,4 +48,48 @@ describe('buildVehiclePopupData', () => { predicted: false }); }); + + it('extracts fields from the correct sources when vehicle and activeTrip share properties', () => { + const vehicle = { + vehicleId: 'v-789', + lastUpdateTime: 1600000200, + predicted: true, + tripHeadsign: 'Wrong Destination' // Testing asymmetry + }; + const activeTrip = { + tripHeadsign: 'Right Destination', + vehicleId: 'wrong-id' // Testing asymmetry + }; + const stopsMap = new Map(); + + const result = buildVehiclePopupData(vehicle, activeTrip, stopsMap); + + expect(result).toEqual({ + nextDestination: 'Right Destination', + vehicleId: 'v-789', + lastUpdateTime: 1600000200, + nextStopName: undefined, + predicted: true + }); + }); + + it('returns undefined nextDestination safely when activeTrip is undefined', () => { + const vehicle = { + vehicleId: 'v-999', + lastUpdateTime: 1600000300, + predicted: false + }; + const activeTrip = undefined; + const stopsMap = new Map(); + + const result = buildVehiclePopupData(vehicle, activeTrip, stopsMap); + + expect(result).toEqual({ + nextDestination: undefined, + vehicleId: 'v-999', + lastUpdateTime: 1600000300, + nextStopName: undefined, + predicted: false + }); + }); }); diff --git a/src/lib/vehicleUtils.js b/src/lib/vehicleUtils.js index e8e07138..cc77ba55 100644 --- a/src/lib/vehicleUtils.js +++ b/src/lib/vehicleUtils.js @@ -95,7 +95,7 @@ export function clearVehicleMarkersMap() { export function buildVehiclePopupData(vehicle, activeTrip, stopsMap) { return { - nextDestination: activeTrip.tripHeadsign, + nextDestination: activeTrip?.tripHeadsign, vehicleId: vehicle.vehicleId, lastUpdateTime: vehicle.lastUpdateTime, nextStopName: stopsMap.get(vehicle.nextStop)?.name, From c4c6fbe1b23601153fdf653d0b2189aa546518e0 Mon Sep 17 00:00:00 2001 From: visha raut Date: Mon, 8 Jun 2026 23:18:25 +0530 Subject: [PATCH 2/4] fix: add null safeguard and source-asymmetry test for buildVehiclePopupData --- src/lib/__tests__/vehicleUtils.test.js | 44 ++++++++++++++++++++++++++ src/lib/vehicleUtils.js | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/lib/__tests__/vehicleUtils.test.js b/src/lib/__tests__/vehicleUtils.test.js index 5a260723..0378b134 100644 --- a/src/lib/__tests__/vehicleUtils.test.js +++ b/src/lib/__tests__/vehicleUtils.test.js @@ -72,6 +72,50 @@ describe('buildVehiclePopupData', () => { predicted: false }); }); + + it('extracts fields from the correct sources when vehicle and activeTrip share properties', () => { + const vehicle = { + vehicleId: 'v-789', + lastUpdateTime: 1600000200, + predicted: true, + tripHeadsign: 'Wrong Destination' // Testing asymmetry + }; + const activeTrip = { + tripHeadsign: 'Right Destination', + vehicleId: 'wrong-id' // Testing asymmetry + }; + const stopsMap = new Map(); + + const result = buildVehiclePopupData(vehicle, activeTrip, stopsMap); + + expect(result).toEqual({ + nextDestination: 'Right Destination', + vehicleId: 'v-789', + lastUpdateTime: 1600000200, + nextStopName: undefined, + predicted: true + }); + }); + + it('returns undefined nextDestination safely when activeTrip is undefined', () => { + const vehicle = { + vehicleId: 'v-999', + lastUpdateTime: 1600000300, + predicted: false + }; + const activeTrip = undefined; + const stopsMap = new Map(); + + const result = buildVehiclePopupData(vehicle, activeTrip, stopsMap); + + expect(result).toEqual({ + nextDestination: undefined, + vehicleId: 'v-999', + lastUpdateTime: 1600000300, + nextStopName: undefined, + predicted: false + }); + }); }); // This suite used to drive the now-deleted single-route `updateVehicleMarkers` diff --git a/src/lib/vehicleUtils.js b/src/lib/vehicleUtils.js index 3cbb6b0d..4c679bc7 100644 --- a/src/lib/vehicleUtils.js +++ b/src/lib/vehicleUtils.js @@ -267,7 +267,7 @@ export function removeVehicleMarkersForRoutes(routeIds, mapProvider) { export function buildVehiclePopupData(vehicle, activeTrip, stopsMap) { return { - nextDestination: activeTrip.tripHeadsign, + nextDestination: activeTrip?.tripHeadsign, vehicleId: vehicle.vehicleId, lastUpdateTime: vehicle.lastUpdateTime, nextStopName: stopsMap.get(vehicle.nextStop)?.name, From ebc4768502008f9ec902293ef2c009162a68a103 Mon Sep 17 00:00:00 2001 From: visha raut Date: Sat, 1 Aug 2026 10:47:18 +0530 Subject: [PATCH 3/4] fix: update vehicle label precondition comment and add null safeguard --- src/lib/Provider/OpenStreetMapProvider.svelte.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib/Provider/OpenStreetMapProvider.svelte.js b/src/lib/Provider/OpenStreetMapProvider.svelte.js index c631cf70..5cba6280 100644 --- a/src/lib/Provider/OpenStreetMapProvider.svelte.js +++ b/src/lib/Provider/OpenStreetMapProvider.svelte.js @@ -26,11 +26,10 @@ import { t } from 'svelte-i18n'; import { ROUTE_PANE_Z_INDEX } from '$lib/mapPanes.js'; // activeTrip is always truthy here: the sole caller (vehicleUtils.js) guards on -// it, and buildVehiclePopupData reads activeTrip.tripHeadsign without optional -// chaining. Keep this contract consistent rather than implying null is expected. +// it. The optional chaining here and in buildVehiclePopupData is belt-and-braces. function getVehicleLabel(activeTrip) { const translate = get(t); - return activeTrip.tripHeadsign + return activeTrip?.tripHeadsign ? translate('vehicle.to_headsign', { values: { headsign: activeTrip.tripHeadsign } }) : translate('vehicle.label'); } From c04edfebd0b731940c1319edb2ba5e74602f7056 Mon Sep 17 00:00:00 2001 From: visha raut Date: Sat, 1 Aug 2026 10:55:45 +0530 Subject: [PATCH 4/4] test: add conflicting lastUpdateTime and predicted values to asymmetry test --- src/lib/__tests__/vehicleUtils.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/__tests__/vehicleUtils.test.js b/src/lib/__tests__/vehicleUtils.test.js index 5aa6180a..bcb83229 100644 --- a/src/lib/__tests__/vehicleUtils.test.js +++ b/src/lib/__tests__/vehicleUtils.test.js @@ -82,7 +82,9 @@ describe('buildVehiclePopupData', () => { }; const activeTrip = { tripHeadsign: 'Right Destination', - vehicleId: 'wrong-id' // Testing asymmetry + vehicleId: 'wrong-id', // Testing asymmetry + lastUpdateTime: 999999999, + predicted: false }; const stopsMap = new Map();