Files
immich-folio/lib/__tests__/mapPrecision.test.ts
Ralksta a813433891 release: v0.13.0 (#535)
Twenty-nine commits since v0.12.0. See CHANGELOG.md for the full list
and the upgrade notes.

Ten additions — the SEO package (site URL, robots.txt, sitemap.xml,
JSON-LD), slideshow mode, opt-in original downloads, copy-link,
previous/next album navigation, alt text from the Immich description,
per-album location precision, the update notice, a Help tab, and a
subpage cover grid separate from its photo grid. Two fixes: CJK album
slugs, and the lightbox control bar.

Photo of the Day (#476) was built on `dev` and reverted as not planned;
it never appears in a release.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01DmsHVRL9yQvckUB1ZpVWre

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 10:08:12 +02:00

133 lines
4.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
placeLabel,
isLocationPrecision,
strictestPrecision,
quantiseCoordinate,
applyPrecision,
LOCATION_PRECISIONS,
type LocationPrecision,
} from '@/lib/mapPrecision';
describe('isLocationPrecision', () => {
it.each(LOCATION_PRECISIONS)('accepts %s', (level) => {
expect(isLocationPrecision(level)).toBe(true);
});
it.each(['', 'EXACT', 'town', 'precise', 'none'])('rejects %s', (value) => {
expect(isLocationPrecision(value)).toBe(false);
});
});
describe('strictestPrecision', () => {
it.each([
[['exact', 'city'], 'city'],
[['city', 'country'], 'country'],
[['exact', 'hidden'], 'hidden'],
[['country', 'city', 'exact'], 'country'],
[['exact'], 'exact'],
[['exact', 'exact'], 'exact'],
] as [LocationPrecision[], LocationPrecision][])('%s → %s', (levels, expected) => {
expect(strictestPrecision(levels)).toBe(expected);
});
it('is order-independent', () => {
expect(strictestPrecision(['country', 'exact'])).toBe(strictestPrecision(['exact', 'country']));
});
/** Nothing contributed, so there is nothing to place. */
it('treats an empty list as hidden', () => {
expect(strictestPrecision([])).toBe('hidden');
});
});
describe('quantiseCoordinate', () => {
it('leaves an exact coordinate untouched', () => {
expect(quantiseCoordinate(52.516272, 'exact')).toBe(52.516272);
});
it('snaps to 0.05° for city', () => {
expect(quantiseCoordinate(52.516272, 'city')).toBe(52.5);
expect(quantiseCoordinate(13.377704, 'city')).toBe(13.4);
});
it('snaps to 1° for country', () => {
expect(quantiseCoordinate(52.516272, 'country')).toBe(53);
expect(quantiseCoordinate(13.377704, 'country')).toBe(13);
});
it('leaves no floating-point tail', () => {
for (const value of [52.9123, 13.0001, -3.3333, 0.049]) {
const quantised = quantiseCoordinate(value, 'city');
expect(String(quantised)).toMatch(/^-?\d+(\.\d{1,2})?$/);
}
});
it('works south and west of zero', () => {
expect(quantiseCoordinate(-33.918861, 'city')).toBe(-33.9);
expect(quantiseCoordinate(-118.24368, 'country')).toBe(-118);
});
/**
* The property that matters: the output is a fixed grid, so asking twice
* cannot average back to the true position.
*/
it('is stable across repeated calls', () => {
const value = 47.376887;
const answers = new Set(Array.from({ length: 50 }, () => quantiseCoordinate(value, 'city')));
expect(answers.size).toBe(1);
});
it('places nearby points on the same grid node, so one album does not stand out', () => {
const garden = [52.5161, 52.5169, 52.5152].map((v) => quantiseCoordinate(v, 'city'));
expect(new Set(garden).size).toBe(1);
});
it('moves a coordinate far enough to stop naming a property', () => {
const exact = 52.516272;
expect(Math.abs(quantiseCoordinate(exact, 'city') - exact)).toBeGreaterThan(0.01);
});
});
describe('applyPrecision', () => {
const berlin = { lat: 52.516272, lng: 13.377704 };
it('quantises both axes', () => {
expect(applyPrecision(berlin, 'city')).toEqual({ lat: 52.5, lng: 13.4 });
});
it('passes an exact position through', () => {
expect(applyPrecision(berlin, 'exact')).toEqual(berlin);
});
/** Not {0,0} — the caller must drop the marker, not place it in the Atlantic. */
it('returns null for hidden', () => {
expect(applyPrecision(berlin, 'hidden')).toBeNull();
});
});
/**
* Quantising the coordinates while still naming the city left the label more
* precise than the position it was meant to blur: a 1° grid cell is ~100 km,
* and "Kloster Chorin" is a village.
*/
describe('placeLabel', () => {
const place = { city: 'Chorin', country: 'Germany' };
it('keeps the city at exact', () => {
expect(placeLabel('exact', place)).toEqual({ city: 'Chorin', country: 'Germany' });
});
it('keeps the city at city precision, which is roughly what a city name says', () => {
expect(placeLabel('city', place)).toEqual({ city: 'Chorin', country: 'Germany' });
});
it('drops the city at country precision', () => {
expect(placeLabel('country', place)).toEqual({ city: '', country: 'Germany' });
});
it('drops both when the marker is hidden, so a caller cannot leak one by accident', () => {
expect(placeLabel('hidden', place)).toEqual({ city: '', country: '' });
});
});