This commit is contained in:
Andras Schmelczer 2026-05-09 09:26:40 +01:00
parent 701c17a703
commit f114ada255
44 changed files with 5264 additions and 1674 deletions

View file

@ -1,11 +1,12 @@
import { describe, expect, it } from 'vitest';
import { existsSync } from 'fs';
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import {
DENSITY_GRADIENT,
ENUM_PALETTE,
FEATURE_GRADIENT,
MAP_BOUNDS,
POI_CATEGORY_LOGOS,
SMALLEST_VISIBLE_HEXAGON_RESOLUTION,
} from './consts';
@ -13,6 +14,8 @@ import {
emojiToTwemojiUrl,
enumIndexToColor,
getBoundsFromViewState,
getBoundsWithBottomScreenInset,
getLatitudeAtVerticalPixelOffset,
getFeatureFillColor,
getMapCenterForTargetScreenPoint,
getPoiIconUrl,
@ -48,21 +51,41 @@ describe('map utilities', () => {
expect(centered.latitude).toBeLessThan(51.5);
});
it('builds twemoji URLs and wraps enum colors', () => {
expect(emojiToTwemojiUrl('🛒')).toBe('/assets/twemoji/1f6d2.png');
expect(emojiToTwemojiUrl('')).toBe('/assets/twemoji/1f4cd.png');
expect(enumIndexToColor(ENUM_PALETTE.length)).toEqual(ENUM_PALETTE[0]);
it('expands the southern map bound by a covered screen area', () => {
const shiftedSouth = getLatitudeAtVerticalPixelOffset(MAP_BOUNDS[1], 5.5, 320);
const shiftedNorth = getLatitudeAtVerticalPixelOffset(MAP_BOUNDS[1], 5.5, -320);
const expandedBounds = getBoundsWithBottomScreenInset(MAP_BOUNDS, 5.5, 320);
expect(shiftedSouth).toBeLessThan(MAP_BOUNDS[1]);
expect(shiftedNorth).toBeGreaterThan(MAP_BOUNDS[1]);
expect(expandedBounds[0]).toBe(MAP_BOUNDS[0]);
expect(expandedBounds[1]).toBeCloseTo(shiftedSouth, 6);
expect(expandedBounds[2]).toBe(MAP_BOUNDS[2]);
expect(expandedBounds[3]).toBe(MAP_BOUNDS[3]);
expect(getBoundsWithBottomScreenInset(MAP_BOUNDS, 5.5, 0)).toEqual(MAP_BOUNDS);
});
it('prefers POI category logos before falling back to emoji icons', () => {
expect(getPoiIconUrl('Waitrose', '🛒')).toBe('/assets/poi-icons/brands/waitrose_24px.svg');
it('builds twemoji URLs and wraps enum colors', () => {
expect(emojiToTwemojiUrl('🛒')).toBe('/assets/twemoji/1f6d2.png');
expect(() => emojiToTwemojiUrl('')).toThrow('Cannot build a Twemoji URL without an emoji');
expect(enumIndexToColor(ENUM_PALETTE.length, ENUM_PALETTE)).toEqual(ENUM_PALETTE[0]);
});
it('resolves POI category logos and rejects unknown icon categories', () => {
expect(getPoiIconUrl('Waitrose', '🛒')).toBe('/assets/poi-icons/logos/waitrose.svg');
expect(getPoiIconUrl('Iceland', '🛒', 'The Food Warehouse')).toBe(
'/assets/poi-icons/brands/iceland_food_warehouse_24px.svg'
'/assets/poi-icons/logos/the_food_warehouse.png'
);
expect(getPoiIconUrl("Sainsbury's", '🛒', undefined, 'Sainsburys Earlsfield Local')).toBe(
'/assets/poi-icons/brands/sainsburys_local_24px.svg'
'/assets/poi-icons/brands_2024/sainsburys_local.svg'
);
expect(getPoiIconUrl('Costco', '🛒')).toBe('/assets/poi-icons/logos/costco.svg');
expect(getPoiIconUrl('M&S', '🛒', undefined, 'M&S Simply Food')).toBe(
'/assets/poi-icons/visuals/mns.svg'
);
expect(() => getPoiIconUrl('Unknown category', '🛒')).toThrow(
"Missing POI icon for category 'Unknown category'"
);
expect(getPoiIconUrl('Unknown category', '🛒')).toBe('/assets/twemoji/1f6d2.png');
});
it('keeps POI icon URLs bundled locally', () => {
@ -74,6 +97,43 @@ describe('map utilities', () => {
).toEqual([]);
});
it('does not use pin-shaped SVGs for branded POI logos', () => {
const pinSignatures = ['viewBox="0 0 400 520"', 'C 18.914 185.931'];
const svgUrls = [
...new Set(
Object.values(POI_CATEGORY_LOGOS)
.filter((url) => url.startsWith('/assets/poi-icons/'))
.filter((url) => url.endsWith('.svg'))
),
];
expect(
svgUrls.filter((url) => {
const content = readFileSync(join(process.cwd(), 'public', url.slice(1)), 'utf8');
return pinSignatures.some((signature) => content.includes(signature));
})
).toEqual([]);
});
it('keeps bundled SVG logos large enough for the map icon atlas', () => {
const svgUrls = [
...new Set(
Object.values(POI_CATEGORY_LOGOS)
.filter((url) => url.startsWith('/assets/poi-icons/'))
.filter((url) => url.endsWith('.svg'))
),
];
expect(
svgUrls.filter((url) => {
const content = readFileSync(join(process.cwd(), 'public', url.slice(1)), 'utf8');
const width = Number(content.match(/width="([0-9.]+)/)?.[1]);
const height = Number(content.match(/height="([0-9.]+)/)?.[1]);
return Math.max(width, height) < 256;
})
).toEqual([]);
});
it('returns fallback, filtered, enum, feature, and density colors', () => {
expect(
getFeatureFillColor(