import { describe, it, expect } from 'vitest'; import { geoJsonRings, geoJsonPositions, type GeoJsonFeatureCollection } from './map-geojson'; describe('geoJsonRings', () => { it('returns nothing for empty input', () => { expect(geoJsonRings(null)).toEqual([]); expect(geoJsonRings(undefined)).toEqual([]); }); it('swaps GeoJSON [lng, lat] into { lat, lng }', () => { // The classic sideways-map bug. GeoJSON is longitude-first. const rings = geoJsonRings({ type: 'LineString', coordinates: [ [-51.23, -30.03], [-50.99, -29.94], ], }); expect(rings[0].points[0]).toEqual({ lng: -51.23, lat: -30.03 }); }); it('marks polygons as closed and lines as open', () => { const polygon = geoJsonRings({ type: 'Polygon', coordinates: [ [ [0, 0], [1, 0], [1, 1], [0, 0], ], ], }); const line = geoJsonRings({ type: 'LineString', coordinates: [ [0, 0], [1, 1], ], }); expect(polygon[0].closed).toBe(true); expect(line[0].closed).toBe(false); }); it('reads a polygon with a hole as two rings', () => { const rings = geoJsonRings({ type: 'Polygon', coordinates: [ [ [0, 0], [4, 0], [4, 4], [0, 0], ], [ [1, 1], [2, 1], [2, 2], [1, 1], ], ], }); expect(rings).toHaveLength(2); }); it('walks a MultiPolygon down to its rings', () => { const rings = geoJsonRings({ type: 'MultiPolygon', coordinates: [ [ [ [0, 0], [1, 0], [1, 1], [0, 0], ], ], [ [ [5, 5], [6, 5], [6, 6], [5, 5], ], ], ], }); expect(rings).toHaveLength(2); expect(rings.every(ring => ring.closed)).toBe(true); }); it('reads a FeatureCollection', () => { const collection: GeoJsonFeatureCollection = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { nome: 'Porto Alegre' }, geometry: { type: 'Polygon', coordinates: [ [ [-51.3, -30.1], [-51.1, -30.1], [-51.1, -29.9], [-51.3, -30.1], ], ], }, }, ], }; const rings = geoJsonRings(collection); expect(rings).toHaveLength(1); expect(rings[0].points).toHaveLength(4); }); it('descends into a GeometryCollection', () => { const rings = geoJsonRings({ type: 'GeometryCollection', geometries: [ { type: 'LineString', coordinates: [ [0, 0], [1, 1], ], }, { type: 'LineString', coordinates: [ [2, 2], [3, 3], ], }, ], }); expect(rings).toHaveLength(2); }); it('skips a feature with no geometry', () => { expect( geoJsonRings({ type: 'FeatureCollection', features: [{ type: 'Feature', geometry: null }], }) ).toEqual([]); }); it('drops runs too short to draw', () => { expect(geoJsonRings({ type: 'Point', coordinates: [1, 2] })).toEqual([]); }); }); describe('geoJsonPositions', () => { it('flattens every coordinate for bounds fitting', () => { const positions = geoJsonPositions({ type: 'MultiLineString', coordinates: [ [ [0, 0], [1, 1], ], [ [2, 2], [3, 3], ], ], }); expect(positions).toHaveLength(4); expect(positions[3]).toEqual({ lng: 3, lat: 3 }); }); });