import { describe, expect, it } from 'vitest'; import { DEFAULT_STYLE_ID, STYLES, isStyleId, rewriteStyle, styleUrl } from './mapStyles'; // Mirrors the real OFM style JSONs (verified against tiles.openfreemap.org): same // glyphs/sprite values and source shapes, no attribution anywhere. const RAW_OFM_STYLE = { version: 8, glyphs: 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf', sprite: 'https://tiles.openfreemap.org/sprites/ofm_f384/ofm', sources: { openmaptiles: { type: 'vector', url: 'https://tiles.openfreemap.org/planet' }, ne2_shaded: { maxzoom: 6, tileSize: 256, tiles: ['https://tiles.openfreemap.org/natural_earth/ne2sr/{z}/{x}/{y}.png'], type: 'raster', }, }, layers: [], }; describe('STYLES registry', () => { it('lists exactly the five OFM styles', () => { expect(STYLES.map((s) => s.id)).toEqual(['liberty', 'bright', 'positron', 'dark', 'fiord']); for (const s of STYLES) expect(s.label.length).toBeGreaterThan(0); }); it('defaults to fiord', () => { expect(DEFAULT_STYLE_ID).toBe('fiord'); }); it('isStyleId accepts only registered ids and styleUrl points at local files', () => { for (const s of STYLES) { expect(isStyleId(s.id)).toBe(true); expect(styleUrl(s.id)).toBe(`/styles/${s.id}.json`); } expect(isStyleId('nope')).toBe(false); }); }); describe('rewriteStyle', () => { it('rewrites glyphs and sprite to local paths, leaves tiles remote', () => { const out = rewriteStyle(RAW_OFM_STYLE) as typeof RAW_OFM_STYLE; expect(out.glyphs).toBe('/fonts/{fontstack}/{range}.pbf'); expect(out.sprite).toBe('/sprites/ofm'); // Vector + raster tile urls must stay remote (tiles are not self-hosted yet). const vector = out.sources.openmaptiles as { url: string }; expect(vector.url).toContain('tiles.openfreemap.org/planet'); const raster = out.sources.ne2_shaded as { tiles: string[] }; expect(raster.tiles[0]).toContain('tiles.openfreemap.org/natural_earth/ne2sr/'); }); it('adds OSM attribution to every source lacking one, without touching others', () => { const out = rewriteStyle(RAW_OFM_STYLE) as typeof RAW_OFM_STYLE; for (const src of Object.values(out.sources) as Array>) { expect(src.attribution).toContain('OpenStreetMap'); } // A source that already has an attribution keeps it. const withAttr = { ...RAW_OFM_STYLE, sources: { a: { type: 'vector', url: 'x', attribution: 'custom' } }, }; const out2 = rewriteStyle(withAttr) as { sources: Record }; expect(out2.sources.a.attribution).toBe('custom'); }); it('returns non-objects unchanged and does not mutate the input', () => { expect(rewriteStyle(null)).toBeNull(); expect(rewriteStyle('nope')).toBe('nope'); const before = JSON.stringify(RAW_OFM_STYLE); rewriteStyle(RAW_OFM_STYLE); expect(JSON.stringify(RAW_OFM_STYLE)).toBe(before); }); });