LGTM
This commit is contained in:
parent
701c17a703
commit
f114ada255
44 changed files with 5264 additions and 1674 deletions
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue