diff --git a/src/hooks.server.js b/src/hooks.server.js index 979ddb30..4dde6066 100644 --- a/src/hooks.server.js +++ b/src/hooks.server.js @@ -1,19 +1,29 @@ import oba from '$lib/obaSdk.js'; let routesCache = null; +let cacheTimestamp = null; +const CACHE_EXPIRATION_MS = 5 * 60 * 1000; // Cache expires every 5 minutes +/** + * Fetches routes data from the OneBusAway (OBA) SDK. + * Retrieves all agencies and their corresponding routes. + * Caches the results to optimize performance. + */ async function fetchRoutesData() { try { const agenciesResponse = await oba.agenciesWithCoverage.list(); const agencies = agenciesResponse.data.list; + // Fetch routes for each agency concurrently const routesPromises = agencies.map(async (agency) => { const routesResponse = await oba.routesForAgency.list(agency.agencyId); const routes = routesResponse.data.list; const references = routesResponse.data.references; + // Create a map of agency references for quick lookups const agencyReferenceMap = new Map(references.agencies.map((agency) => [agency.id, agency])); + // Attach agency info to each route routes.forEach((route) => { route.agencyInfo = agencyReferenceMap.get(route.agencyId); }); @@ -21,27 +31,42 @@ async function fetchRoutesData() { return routes; }); - const routes = await Promise.all(routesPromises); - return routes.flat(); + // Wait for all routes to be fetched and flatten the results + const routes = (await Promise.all(routesPromises)).flat(); + + // Update cache and timestamp + routesCache = routes; + cacheTimestamp = Date.now(); + + return routes; } catch (error) { console.error('Error fetching routes:', error); return null; } } +/** + * Ensures the routes data is loaded and cached. + * Refreshes the cache if it is expired. + */ async function preloadRoutesData() { - if (!routesCache) { - routesCache = await fetchRoutesData(); + const isCacheExpired = !cacheTimestamp || (Date.now() - cacheTimestamp > CACHE_EXPIRATION_MS); + if (!routesCache || isCacheExpired) { + await fetchRoutesData(); } } -preloadRoutesData(); - +/** + * Middleware hook that ensures routes data is available before handling the request. + */ export async function handle({ event, resolve }) { await preloadRoutesData(); return resolve(event); } +/** + * Returns the cached routes data. + */ export function getRoutesCache() { return routesCache; } diff --git a/src/tests/lib/tests/fetchRoutesData.test.js b/src/tests/lib/tests/fetchRoutesData.test.js new file mode 100644 index 00000000..280e0e15 --- /dev/null +++ b/src/tests/lib/tests/fetchRoutesData.test.js @@ -0,0 +1,64 @@ +import { fetchRoutesData, getRoutesCache } from '../path-to-your-file.js'; // Update the path as needed + +// Mock the oba SDK to avoid making real API calls +jest.mock('$lib/obaSdk.js', () => ({ + agenciesWithCoverage: { + list: jest.fn().mockResolvedValue({ + data: { + list: [{ agencyId: '1', name: 'Test Agency' }], // Fake agency data for testing + }, + }), + }, + routesForAgency: { + list: jest.fn().mockResolvedValue({ + data: { + list: [{ id: 'route1', agencyId: '1', shortName: 'R1' }], // Fake route data + references: { agencies: [{ id: '1', name: 'Test Agency' }] }, // Fake agency reference + }, + }), + }, +})); + +// Grouping tests related to fetchRoutesData() +describe('fetchRoutesData', () => { + + // Test: Should successfully fetch and return routes + it('should fetch and return routes successfully', async () => { + const routes = await fetchRoutesData(); // Call the function + + // Ensure routes are fetched and not empty + expect(routes).toBeDefined(); + expect(routes.length).toBeGreaterThan(0); + + // Check if the first route has the expected properties + expect(routes[0]).toHaveProperty('id', 'route1'); + expect(routes[0]).toHaveProperty('agencyInfo'); + expect(routes[0].agencyInfo).toHaveProperty('name', 'Test Agency'); + }); + + // Test: Should update the cache after fetching data + it('should update the cache after fetching data', async () => { + await fetchRoutesData(); // Fetch data to populate cache + const cachedRoutes = getRoutesCache(); // Get cached routes + + // Ensure cache exists and contains data + expect(cachedRoutes).toBeDefined(); + expect(cachedRoutes.length).toBeGreaterThan(0); + }); +}); + +/** + * Expected Output When Running Tests: + * + * PASS tests/fetchRoutesData.test.js + * ✓ should fetch and return routes successfully (X ms) + * ✓ should update the cache after fetching data (X ms) + * + * Test Suites: 1 passed, 1 total + * Tests: 2 passed, 2 total + * Snapshots: 0 total + * Time: 0.Xs, estimated Xs + * Ran all test suites. + * + * If a test fails, Jest will show error messages explaining what went wrong. + */