mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-17 07:50:31 +00:00
486 lines
12 KiB
TypeScript
486 lines
12 KiB
TypeScript
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
|
|
import {
|
|
ApiBasedRepository,
|
|
ApiBasedRepositoryCache,
|
|
ApiBasedRepositoryMillisecondTTLs
|
|
} from "../../src/repositories/ApiBasedRepository";
|
|
import { IEta } from "../../src/entities/entities";
|
|
|
|
/**
|
|
* Update the global fetch function to return a specific object.
|
|
* @param obj
|
|
*/
|
|
function updateGlobalFetchMockJson(obj: any) {
|
|
// @ts-ignore
|
|
global.fetch = jest.fn(() => {
|
|
return Promise.resolve({
|
|
json: () => Promise.resolve(obj)
|
|
})
|
|
}) as jest.Mock;
|
|
}
|
|
|
|
/**
|
|
* Reset the global fetch function mock's JSON to return an empty object.
|
|
* @param obj
|
|
*/
|
|
function resetGlobalFetchMockJson() {
|
|
updateGlobalFetchMockJson({})
|
|
}
|
|
|
|
beforeEach(() => {
|
|
resetGlobalFetchMockJson();
|
|
})
|
|
|
|
// Snapshots taken from the Passio GO! API
|
|
const genericEtaDataByStopId = {
|
|
"177666": [
|
|
{
|
|
"OOS": 0,
|
|
"busName": "08",
|
|
"distance": 1,
|
|
"speed": 10.028535400123669,
|
|
"routeBlockId": "142270",
|
|
"actualRouteBlockId": "142270",
|
|
"arrived": null,
|
|
"eta": "10 min ",
|
|
"color": "#000000",
|
|
"bg": "#ffea3f",
|
|
"order": 0,
|
|
"dwell": null,
|
|
"stopsAmount": 2,
|
|
"secondsSpent": 587,
|
|
"etaR": "10",
|
|
"error": null,
|
|
"outdated": 0,
|
|
"routeId": "53966",
|
|
"serviceTime": "",
|
|
"scheduleTimes": [],
|
|
"goShowSchedule": 0,
|
|
"looping": "1",
|
|
"routeGroupId": "6703",
|
|
"busId": 5577,
|
|
"tripId": 751430,
|
|
"deviceId": 402840,
|
|
"created": "2025-01-07 15:00:09",
|
|
"routePointPosition": 6,
|
|
"routeStopPosition": 1,
|
|
"stopRoutePointPosition": 217,
|
|
"timezoneOffset": -10800,
|
|
"busLatLng": [
|
|
33.7933406,
|
|
-117.8539321
|
|
],
|
|
"busProjectionLatlng": {
|
|
"lat": 33.79331052666975,
|
|
"lng": -117.85392945849208
|
|
},
|
|
"busProjectionError": 3,
|
|
"stopId": "177666",
|
|
"theStop": {
|
|
"name": "Chapman Court",
|
|
"position": 3,
|
|
"userId": "263",
|
|
"routeStopId": "1348785",
|
|
"busId": 5577,
|
|
"routeName": "Red Route",
|
|
"shortName": null,
|
|
"routeId": "53966",
|
|
"stopId": "177666"
|
|
}
|
|
},
|
|
{
|
|
"OOS": 0,
|
|
"busName": "07",
|
|
"distance": 1,
|
|
"speed": 12.160256921380398,
|
|
"routeBlockId": "142270",
|
|
"actualRouteBlockId": "142270",
|
|
"arrived": null,
|
|
"eta": "11 min ",
|
|
"color": "#000000",
|
|
"bg": "#ffea3f",
|
|
"order": 0,
|
|
"dwell": null,
|
|
"stopsAmount": 2,
|
|
"secondsSpent": 635,
|
|
"etaR": "11",
|
|
"error": null,
|
|
"outdated": 0,
|
|
"routeId": "53966",
|
|
"serviceTime": "",
|
|
"scheduleTimes": [],
|
|
"goShowSchedule": 0,
|
|
"looping": "1",
|
|
"routeGroupId": "6703",
|
|
"busId": 5576,
|
|
"tripId": 751430,
|
|
"deviceId": 441065,
|
|
"created": "2025-01-07 15:00:10",
|
|
"routePointPosition": 448,
|
|
"routeStopPosition": 4,
|
|
"stopRoutePointPosition": 217,
|
|
"timezoneOffset": -10800,
|
|
"busLatLng": [
|
|
33.7933284,
|
|
-117.855132
|
|
],
|
|
"busProjectionLatlng": {
|
|
"lat": 33.79332033922653,
|
|
"lng": -117.85513217762522
|
|
},
|
|
"busProjectionError": 1,
|
|
"stopId": "177666",
|
|
"theStop": {
|
|
"name": "Chapman Court",
|
|
"position": 3,
|
|
"userId": "263",
|
|
"routeStopId": "1348785",
|
|
"busId": 5576,
|
|
"routeName": "Red Route",
|
|
"shortName": null,
|
|
"routeId": "53966",
|
|
"stopId": "177666"
|
|
}
|
|
},
|
|
]
|
|
}
|
|
const genericShuttleDataBySystemId = {
|
|
"alertCRC": "23c1b91c",
|
|
"buses": {
|
|
"402840": [
|
|
{
|
|
"deviceId": 402840,
|
|
"created": "08:24 PM",
|
|
"createdTime": "08:24 PM",
|
|
"paxLoad": 0,
|
|
"bus": "08",
|
|
"busId": 5577,
|
|
"userId": "263",
|
|
"routeBlockId": "142270",
|
|
"latitude": "33.791781800",
|
|
"longitude": "-117.858964600",
|
|
"calculatedCourse": "351.796001302109",
|
|
"outOfService": 0,
|
|
"more": "102",
|
|
"totalCap": 20,
|
|
"color": "#d62728",
|
|
"busName": "08",
|
|
"busType": "",
|
|
"routeId": "53966",
|
|
"route": "Red Route",
|
|
"outdated": 0
|
|
}
|
|
],
|
|
"404873": [
|
|
{
|
|
"deviceId": 404873,
|
|
"created": "08:24 PM",
|
|
"createdTime": "08:24 PM",
|
|
"paxLoad": 0,
|
|
"bus": "10",
|
|
"busId": 7105,
|
|
"userId": "263",
|
|
"routeBlockId": "142270",
|
|
"latitude": "33.789331300",
|
|
"longitude": "-117.888790600",
|
|
"calculatedCourse": "76.005762226701",
|
|
"outOfService": 0,
|
|
"more": "101",
|
|
"totalCap": 20,
|
|
"color": "#d62728",
|
|
"busName": "10",
|
|
"busType": "",
|
|
"routeId": "53966",
|
|
"route": "Red Route",
|
|
"outdated": 0
|
|
}
|
|
],
|
|
"421421": [
|
|
{
|
|
"deviceId": 421421,
|
|
"created": "08:24 PM",
|
|
"createdTime": "08:24 PM",
|
|
"paxLoad": 0,
|
|
"bus": "17",
|
|
"busId": 12502,
|
|
"userId": "263",
|
|
"routeBlockId": "142660",
|
|
"latitude": "33.790699500",
|
|
"longitude": "-117.890385500",
|
|
"calculatedCourse": "10.65684824528148",
|
|
"outOfService": 0,
|
|
"more": "101",
|
|
"totalCap": 32,
|
|
"color": "#bd9e39",
|
|
"busName": "17",
|
|
"busType": "Shuttle Bus",
|
|
"routeId": "54256",
|
|
"route": "Gold Route",
|
|
"outdated": 0
|
|
}
|
|
],
|
|
"441065": [
|
|
{
|
|
"deviceId": 441065,
|
|
"created": "08:19 PM",
|
|
"createdTime": "08:19 PM",
|
|
"paxLoad": 0,
|
|
"bus": "07",
|
|
"busId": 5576,
|
|
"userId": "263",
|
|
"routeBlockId": "142270",
|
|
"latitude": "33.793278900",
|
|
"longitude": "-117.852629400",
|
|
"calculatedCourse": "299.74488110904485",
|
|
"outOfService": 0,
|
|
"more": "22",
|
|
"totalCap": 20,
|
|
"color": "#d62728",
|
|
"busName": "07",
|
|
"busType": "",
|
|
"routeId": "53966",
|
|
"route": "Red Route",
|
|
"outdated": 0
|
|
}
|
|
]
|
|
},
|
|
"microtime": 0.023222923278808594,
|
|
"time": {
|
|
"263": "08:24 PM"
|
|
}
|
|
}
|
|
|
|
describe("getEtaForShuttleAndStopId", () => {
|
|
test("getEtaForShuttleAndStopId returns correct ETA data", async () => {
|
|
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
|
|
const repository = new ApiBasedRepository();
|
|
const result = await repository.getEtaForShuttleAndStopId("5577", "177666");
|
|
|
|
expect(result?.secondsRemaining).toEqual(587);
|
|
expect(result?.millisecondsSinceEpoch).toBeDefined();
|
|
});
|
|
|
|
test("getEtaForShuttleAndStopId returns null if API call is invalid and cache is empty", async () => {
|
|
const repository = new ApiBasedRepository();
|
|
const result = await repository.getEtaForShuttleAndStopId("5577", "177666");
|
|
|
|
expect(result).toEqual(null);
|
|
});
|
|
});
|
|
|
|
describe("getEtasForShuttleId", () => {
|
|
test("getEtasForShuttleId returns correct ETA data", async () => {
|
|
// Because I'm testing updateEtasForSystemIfTTL separately,
|
|
// stub it out here
|
|
|
|
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
|
|
const initialCache: ApiBasedRepositoryCache = {
|
|
etasForStopId: {},
|
|
etasForShuttleId: {
|
|
"5577": [
|
|
{
|
|
secondsRemaining: 587,
|
|
shuttleId: "5577",
|
|
stopId: "177666",
|
|
millisecondsSinceEpoch: Date.now(),
|
|
}
|
|
]
|
|
},
|
|
};
|
|
|
|
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
etasForShuttleId: 100000,
|
|
etasForStopId: 100000,
|
|
};
|
|
|
|
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
});
|
|
const result = await repository.getEtasForShuttleId("5577");
|
|
|
|
expect(result).toEqual(initialCache.etasForShuttleId);
|
|
});
|
|
|
|
test("getEtasForShuttleId returns empty array if no data available", async () => {
|
|
const repository = new ApiBasedRepository();
|
|
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
});
|
|
const result = await repository.getEtasForShuttleId("5577");
|
|
|
|
expect(result).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("getEtasForStopId", () => {
|
|
test("getEtasForStopId returns correct ETA data", async () => {
|
|
// Because I'm testing updateEtasForSystemIfTTL separately,
|
|
// stub it out here
|
|
|
|
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
|
|
const initialCache: ApiBasedRepositoryCache = {
|
|
etasForStopId: {
|
|
"177666": [
|
|
{
|
|
secondsRemaining: 587,
|
|
shuttleId: "5577",
|
|
stopId: "177666",
|
|
millisecondsSinceEpoch: Date.now(),
|
|
}
|
|
]
|
|
},
|
|
etasForShuttleId: {}
|
|
};
|
|
|
|
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
etasForShuttleId: 100000,
|
|
etasForStopId: 100000,
|
|
};
|
|
|
|
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
});
|
|
const result = await repository.getEtasForStopId("177666");
|
|
|
|
expect(result).toEqual(initialCache.etasForShuttleId);
|
|
});
|
|
|
|
test("getEtasForStopId returns empty array if no data available", async () => {
|
|
const repository = new ApiBasedRepository();
|
|
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
});
|
|
const result = await repository.getEtasForShuttleId("5577");
|
|
|
|
expect(result).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("updateEtasForSystemIfTTL", () => {
|
|
test("updateEtasForSystemIfTTL does nothing if data is not TTL", async () => {
|
|
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
|
|
// If ETA data is not TTL, then don't do anything
|
|
const expectedEta: IEta = {
|
|
secondsRemaining: 587,
|
|
shuttleId: "5577",
|
|
stopId: "177666",
|
|
millisecondsSinceEpoch: Date.now() - 1000,
|
|
};
|
|
|
|
const initialCache: ApiBasedRepositoryCache = {
|
|
etasForShuttleId: {
|
|
"5577": [
|
|
expectedEta,
|
|
],
|
|
},
|
|
etasForStopId: {
|
|
"177666": [
|
|
expectedEta,
|
|
],
|
|
},
|
|
stopsBySystemId: {
|
|
"1": [
|
|
{
|
|
systemId: "1",
|
|
millisecondsSinceEpoch: Date.now() - 1000,
|
|
name: "Chapman Court",
|
|
id: "177666",
|
|
coordinates: {
|
|
latitude: 33.796796,
|
|
longitude: -117.889293
|
|
},
|
|
}
|
|
],
|
|
},
|
|
};
|
|
|
|
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
etasForShuttleId: 100000,
|
|
etasForStopId: 100000,
|
|
};
|
|
|
|
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
await repository.updateEtasForSystemIfTTL("1");
|
|
|
|
const updatedResult = await repository.getEtaForShuttleAndStopId(
|
|
"5577",
|
|
"177666",
|
|
);
|
|
expect(updatedResult?.millisecondsSinceEpoch).toEqual(expectedEta.millisecondsSinceEpoch);
|
|
});
|
|
|
|
test("updateEtasForSystemIfTTL updates all ETA data if data is TTL", async () => {
|
|
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
|
|
const repository = new ApiBasedRepository();
|
|
repository.getStopsBySystemId = jest.fn(async () => {
|
|
return [
|
|
{
|
|
name: "Chapman Court",
|
|
systemId: "1",
|
|
id: "177666",
|
|
coordinates: {
|
|
latitude: 33.796796,
|
|
longitude: -117.889293
|
|
},
|
|
}
|
|
];
|
|
});
|
|
|
|
await repository.updateEtasForSystemIfTTL("1");
|
|
|
|
const updatedResult = await repository.getEtasForStopId("177666");
|
|
expect(updatedResult.length).toEqual(2);
|
|
});
|
|
});
|
|
|
|
describe("getShuttleById", () => {
|
|
test("getShuttleById returns null if unseeded cache", async () => {
|
|
updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
|
|
const initialCache: ApiBasedRepositoryCache = {};
|
|
const repository = new ApiBasedRepository(initialCache);
|
|
|
|
const shuttle = await repository.getShuttleById("5577");
|
|
expect(shuttle).toBeNull();
|
|
});
|
|
|
|
test("getShuttleById returns old data if not expired", async () => {
|
|
updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
|
|
const expectedShuttle = {
|
|
coordinates: {
|
|
latitude: 33.791781,
|
|
longitude: -117.8589646,
|
|
},
|
|
name: "08",
|
|
routeId: "53966",
|
|
systemId: "1",
|
|
id: "5577",
|
|
millisecondsSinceEpoch: Date.now() - 1000,
|
|
}
|
|
|
|
const initialCache: ApiBasedRepositoryCache = {
|
|
shuttleByShuttleId: {
|
|
"5577": expectedShuttle
|
|
}
|
|
};
|
|
|
|
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
shuttleByShuttleId: 100000,
|
|
};
|
|
|
|
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
const shuttle = await repository.getShuttleById("5577");
|
|
|
|
expect(shuttle).toEqual(expectedShuttle);
|
|
});
|
|
|
|
test("getShuttleById returns fresh data if expired", async () => {
|
|
|
|
});
|
|
});
|
|
|