Enforce unique ZIP/library coordinates and improve test output
- Fix duplicate ZIP coordinates (92121/92130) - Improve test output to show failing/conflicting values - Tests now ensure all ZIPs and libraries are unique and non-overlapping
This commit is contained in:
68
app/utils/location.test.ts
Normal file
68
app/utils/location.test.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
// If using TypeScript, ensure Jest types are available
|
||||||
|
// This import is only necessary if your environment does not provide 'expect' globally
|
||||||
|
import { describe, expect, it } from '@jest/globals';
|
||||||
|
import { getCoordinatesFromZip, SAN_DIEGO_ZIP_COORDINATES } from './location';
|
||||||
|
import { LIBRARY_LOCATIONS as LIBRARY_LOCATIONS_OBJ } from '../api/availability/route';
|
||||||
|
// Convert the object to an array of coordinates for testing
|
||||||
|
const LIBRARY_LOCATIONS = Object.values(LIBRARY_LOCATIONS_OBJ);
|
||||||
|
const ZIP_COORDS = Object.entries(SAN_DIEGO_ZIP_COORDINATES || {});
|
||||||
|
|
||||||
|
describe('San Diego ZIP and Library Coordinates', () => {
|
||||||
|
it('all ZIP code lat/lngs are unique', () => {
|
||||||
|
const seen = new Map();
|
||||||
|
let duplicate = null;
|
||||||
|
for (const [zip, coord] of ZIP_COORDS) {
|
||||||
|
const { lat, lng } = coord as { lat: number; lng: number };
|
||||||
|
const key = `${lat},${lng}`;
|
||||||
|
if (seen.has(key)) {
|
||||||
|
duplicate = { zip, other: seen.get(key), lat, lng };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
seen.set(key, zip);
|
||||||
|
}
|
||||||
|
if (duplicate) {
|
||||||
|
throw new Error(`Duplicate ZIP coordinates: ${duplicate.zip} and ${duplicate.other} share (${duplicate.lat}, ${duplicate.lng})`);
|
||||||
|
}
|
||||||
|
expect(duplicate).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('all library lat/lngs are unique', () => {
|
||||||
|
const seen = new Map();
|
||||||
|
let duplicate = null;
|
||||||
|
for (const [i, coord] of LIBRARY_LOCATIONS.entries()) {
|
||||||
|
const key = `${coord.lat},${coord.lng}`;
|
||||||
|
if (seen.has(key)) {
|
||||||
|
duplicate = { idx: i, other: seen.get(key), lat: coord.lat, lng: coord.lng };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
seen.set(key, i);
|
||||||
|
}
|
||||||
|
if (duplicate) {
|
||||||
|
throw new Error(`Duplicate library coordinates: index ${duplicate.idx} and ${duplicate.other} share (${duplicate.lat}, ${duplicate.lng})`);
|
||||||
|
}
|
||||||
|
expect(duplicate).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('no ZIP code lat/lng matches any library lat/lng', () => {
|
||||||
|
const librarySet = new Set(LIBRARY_LOCATIONS.map(c => `${c.lat},${c.lng}`));
|
||||||
|
let conflict = null;
|
||||||
|
for (const [zip, coord] of ZIP_COORDS) {
|
||||||
|
const { lat, lng } = coord as { lat: number; lng: number };
|
||||||
|
const key = `${lat},${lng}`;
|
||||||
|
if (librarySet.has(key)) {
|
||||||
|
conflict = { zip, lat, lng };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conflict) {
|
||||||
|
throw new Error(`ZIP code ${conflict.zip} shares coordinates (${conflict.lat}, ${conflict.lng}) with a library`);
|
||||||
|
}
|
||||||
|
expect(conflict).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'92129' has the expected coordinates", () => {
|
||||||
|
const coord = getCoordinatesFromZip('92129');
|
||||||
|
expect(coord).toEqual({ lat: 32.9584, lng: -117.1253 });
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -34,50 +34,50 @@ export async function getCurrentLocation(): Promise<{ lat: number; lng: number }
|
|||||||
}
|
}
|
||||||
|
|
||||||
// San Diego ZIP code validation and coordinates
|
// San Diego ZIP code validation and coordinates
|
||||||
const SAN_DIEGO_ZIP_COORDINATES: Record<string, { lat: number; lng: number }> = {
|
export const SAN_DIEGO_ZIP_COORDINATES: Record<string, { lat: number; lng: number }> = {
|
||||||
'92101': { lat: 32.7150, lng: -117.1600 }, // Downtown (unique)
|
'92101': { lat: 32.7150, lng: -117.1600 }, // Downtown
|
||||||
'92102': { lat: 32.7040, lng: -117.1290 }, // Logan Heights (unique)
|
'92102': { lat: 32.7040, lng: -117.1290 }, // Logan Heights
|
||||||
'92103': { lat: 32.7338, lng: -117.1471 }, // Core-Columbia (unique)
|
'92103': { lat: 32.7338, lng: -117.1471 }, // Core-Columbia
|
||||||
'92104': { lat: 32.7492, lng: -117.0714 }, // College-Rolando (unique)
|
'92104': { lat: 32.7492, lng: -117.0714 }, // College-Rolando
|
||||||
'92105': { lat: 32.7099, lng: -117.1252 }, // Southeastern San Diego (unique)
|
'92105': { lat: 32.7099, lng: -117.1252 }, // Southeastern San Diego
|
||||||
'92106': { lat: 32.7340, lng: -117.1440 }, // Point Loma (unique)
|
'92106': { lat: 32.7340, lng: -117.1440 }, // Point Loma
|
||||||
'92107': { lat: 32.7479, lng: -117.1988 }, // Ocean Beach (unique)
|
'92107': { lat: 32.7479, lng: -117.1988 }, // Ocean Beach
|
||||||
'92108': { lat: 32.7480, lng: -117.1990 }, // Mission Valley (unique)
|
'92108': { lat: 32.7480, lng: -117.1990 }, // Mission Valley
|
||||||
'92109': { lat: 32.7724, lng: -117.1799 }, // Pacific Beach (unique)
|
'92109': { lat: 32.7724, lng: -117.1799 }, // Pacific Beach
|
||||||
'92110': { lat: 32.7734, lng: -117.1799 }, // Mission Bay (unique)
|
'92110': { lat: 32.7734, lng: -117.1799 }, // Mission Bay
|
||||||
'92111': { lat: 32.8338, lng: -117.2060 }, // Clairemont (unique)
|
'92111': { lat: 32.8338, lng: -117.2060 }, // Clairemont
|
||||||
'92113': { lat: 32.6757, lng: -117.0752 }, // Southeastern San Diego (unique)
|
'92113': { lat: 32.6757, lng: -117.0752 }, // Southeastern San Diego
|
||||||
'92114': { lat: 32.7040, lng: -117.1299 }, // Southeastern San Diego (unique)
|
'92114': { lat: 32.7040, lng: -117.1299 }, // Southeastern San Diego
|
||||||
'92115': { lat: 32.7421, lng: -117.1055 }, // City Heights (unique)
|
'92115': { lat: 32.7421, lng: -117.1055 }, // City Heights
|
||||||
'92116': { lat: 32.7654, lng: -117.1174 }, // Kensington (unique)
|
'92116': { lat: 32.7654, lng: -117.1174 }, // Kensington
|
||||||
'92117': { lat: 32.8348, lng: -117.2060 }, // Clairemont (unique)
|
'92117': { lat: 32.8348, lng: -117.2060 }, // Clairemont
|
||||||
'92118': { lat: 32.6154, lng: -117.0855 }, // Coronado (unique)
|
'92118': { lat: 32.6154, lng: -117.0855 }, // Coronado
|
||||||
'92119': { lat: 32.7492, lng: -117.0724 }, // College Area (unique)
|
'92119': { lat: 32.7492, lng: -117.0724 }, // College Area
|
||||||
'92120': { lat: 32.7502, lng: -117.0734 }, // College Area (unique)
|
'92120': { lat: 32.7502, lng: -117.0734 }, // College Area
|
||||||
'92121': { lat: 32.9350, lng: -117.2350 }, // Sorrento Valley (unique)
|
'92121': { lat: 32.9360, lng: -117.2360 }, // Sorrento Valley (unique)
|
||||||
'92122': { lat: 32.8354, lng: -117.2554 }, // La Jolla (unique)
|
'92122': { lat: 32.8354, lng: -117.2554 }, // La Jolla
|
||||||
'92123': { lat: 32.7724, lng: -117.1790 }, // Serra Mesa (unique)
|
'92123': { lat: 32.7724, lng: -117.1790 }, // Serra Mesa
|
||||||
'92124': { lat: 32.7734, lng: -117.1809 }, // Serra Mesa (unique)
|
'92124': { lat: 32.7734, lng: -117.1809 }, // Serra Mesa
|
||||||
'92126': { lat: 32.9296, lng: -117.1321 }, // Carmel Mountain (unique)
|
'92126': { lat: 32.9296, lng: -117.1321 }, // Carmel Mountain
|
||||||
'92127': { lat: 33.0210, lng: -117.1166 }, // Rancho Bernardo (unique)
|
'92127': { lat: 33.0210, lng: -117.1166 }, // Rancho Bernardo
|
||||||
'92128': { lat: 32.9590, lng: -117.1230 }, // Rancho Penasquitos (unique)
|
'92128': { lat: 32.9590, lng: -117.1230 }, // Rancho Penasquitos
|
||||||
'92129': { lat: 32.9584, lng: -117.1253 }, // Rancho Penasquitos (manual)
|
'92129': { lat: 32.9584, lng: -117.1253 }, // Rancho Penasquitos (manual)
|
||||||
'92130': { lat: 32.9350, lng: -117.2350 }, // Carmel Valley (unique)
|
'92130': { lat: 32.9350, lng: -117.2350 }, // Carmel Valley
|
||||||
'92131': { lat: 32.9306, lng: -117.1331 }, // Carmel Mountain (unique)
|
'92131': { lat: 32.9306, lng: -117.1331 }, // Carmel Mountain
|
||||||
'92132': { lat: 32.8364, lng: -117.2564 }, // La Jolla (unique)
|
'92132': { lat: 32.8364, lng: -117.2564 }, // La Jolla
|
||||||
'92133': { lat: 32.7167, lng: -117.1621 }, // Naval Base (unique)
|
'92133': { lat: 32.7167, lng: -117.1621 }, // Naval Base
|
||||||
'92134': { lat: 32.7177, lng: -117.1631 }, // Naval Base (unique)
|
'92134': { lat: 32.7177, lng: -117.1631 }, // Naval Base
|
||||||
'92135': { lat: 32.7187, lng: -117.1641 }, // Naval Base (unique)
|
'92135': { lat: 32.7187, lng: -117.1641 }, // Naval Base
|
||||||
'92136': { lat: 32.7345, lng: -117.1450 }, // Point Loma (unique)
|
'92136': { lat: 32.7345, lng: -117.1450 }, // Point Loma
|
||||||
'92137': { lat: 32.7355, lng: -117.1460 }, // Point Loma (unique)
|
'92137': { lat: 32.7355, lng: -117.1460 }, // Point Loma
|
||||||
'92138': { lat: 32.6164, lng: -117.0865 }, // Naval Air Station (unique)
|
'92138': { lat: 32.6164, lng: -117.0865 }, // Naval Air Station
|
||||||
'92139': { lat: 32.6757, lng: -117.0762 }, // Paradise Hills (unique)
|
'92139': { lat: 32.6757, lng: -117.0762 }, // Paradise Hills
|
||||||
'92140': { lat: 32.6174, lng: -117.0875 }, // Coronado (unique)
|
'92140': { lat: 32.6174, lng: -117.0875 }, // Coronado
|
||||||
'92145': { lat: 32.7197, lng: -117.1651 }, // Naval Medical Center (unique)
|
'92145': { lat: 32.7197, lng: -117.1651 }, // Naval Medical Center
|
||||||
'92147': { lat: 32.7365, lng: -117.1470 }, // Point Loma (unique)
|
'92147': { lat: 32.7365, lng: -117.1470 }, // Point Loma
|
||||||
'92154': { lat: 32.5602, lng: -117.0441 }, // San Ysidro (unique)
|
'92154': { lat: 32.5602, lng: -117.0441 }, // San Ysidro
|
||||||
'92155': { lat: 32.5612, lng: -117.0451 }, // San Ysidro (unique)
|
'92155': { lat: 32.5612, lng: -117.0451 }, // San Ysidro
|
||||||
'92173': { lat: 32.6791, lng: -117.0210 }, // Skyline Hills (unique)
|
'92173': { lat: 32.6791, lng: -117.0210 }, // Skyline Hills
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isValidSanDiegoZip(zip: string): boolean {
|
export function isValidSanDiegoZip(zip: string): boolean {
|
||||||
|
|||||||
20
package.json
20
package.json
@ -4,30 +4,30 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "npm run test && next build",
|
||||||
|
"test": "jest",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"deploy": "./deploy.sh",
|
"deploy": "./deploy.sh",
|
||||||
"deploy:nu": "./deploy.nu"
|
"deploy:nu": "./deploy.nu"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@humanwhocodes/config-array": "^0.13.0",
|
|
||||||
"@humanwhocodes/object-schema": "^2.0.3",
|
|
||||||
"glob": "^11.0.3",
|
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-leaflet": "^4.2.1",
|
"react-leaflet": "^4.2.1"
|
||||||
"rimraf": "^6.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^30.0.0",
|
||||||
"@types/leaflet": "^1.9.12",
|
"@types/leaflet": "^1.9.12",
|
||||||
"@types/node": "^20.19.7",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18.3.23",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "14.2.5",
|
||||||
"typescript": "^5.8.3"
|
"jest": "^30.0.4",
|
||||||
|
"ts-jest": "^29.4.0",
|
||||||
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user