New renderer-agnostic package with zero dependencies: - Tile configs (base layers, overlay layers) - Color palettes (surface, highway, smoothness, tracktype, cycleway, bikeroute, elevation, maxspeed) — 8 color maps + 3 color functions - POI category definitions (9 categories with Overpass queries, icons, colors, profile mappings) - Z-index layering constants - Snap distance constant Updated 15 consuming files to import from @trails-cool/map-core. Deleted poi-categories.ts and z-index.ts from the Planner (fully moved). packages/map re-exports tile configs from map-core for backwards compat. All 117 tests pass, no user-facing changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
104 lines
3.4 KiB
TypeScript
104 lines
3.4 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { buildQuery, parseResponse, deduplicateById, type Poi } from "./overpass.ts";
|
|
import { poiCategories } from "@trails-cool/map-core";
|
|
|
|
describe("buildQuery", () => {
|
|
it("builds Overpass QL with bbox and category union", () => {
|
|
const bbox = { south: 52.5, west: 13.3, north: 52.6, east: 13.5 };
|
|
const categories = poiCategories.filter((c) => c.id === "drinking_water");
|
|
const query = buildQuery(bbox, categories);
|
|
|
|
expect(query).toContain("[out:json]");
|
|
expect(query).toContain("[bbox:52.5,13.3,52.6,13.5]");
|
|
expect(query).toContain('amenity"="drinking_water"');
|
|
expect(query).toContain("out center qt 100");
|
|
});
|
|
|
|
it("combines multiple categories into a single union", () => {
|
|
const bbox = { south: 52.5, west: 13.3, north: 52.6, east: 13.5 };
|
|
const categories = poiCategories.filter((c) => ["drinking_water", "camping"].includes(c.id));
|
|
const query = buildQuery(bbox, categories);
|
|
|
|
expect(query).toContain("drinking_water");
|
|
expect(query).toContain("camp_site");
|
|
});
|
|
});
|
|
|
|
describe("parseResponse", () => {
|
|
it("parses nodes into Poi objects", () => {
|
|
const data = {
|
|
elements: [
|
|
{
|
|
type: "node",
|
|
id: 123,
|
|
lat: 52.52,
|
|
lon: 13.405,
|
|
tags: { amenity: "drinking_water", name: "Brunnen" },
|
|
},
|
|
],
|
|
};
|
|
const categories = poiCategories.filter((c) => c.id === "drinking_water");
|
|
const pois = parseResponse(data, categories);
|
|
|
|
expect(pois).toHaveLength(1);
|
|
expect(pois[0]!.id).toBe(123);
|
|
expect(pois[0]!.name).toBe("Brunnen");
|
|
expect(pois[0]!.category).toBe("drinking_water");
|
|
expect(pois[0]!.lat).toBe(52.52);
|
|
});
|
|
|
|
it("uses center for way/relation elements", () => {
|
|
const data = {
|
|
elements: [
|
|
{
|
|
type: "way",
|
|
id: 456,
|
|
center: { lat: 52.51, lon: 13.39 },
|
|
tags: { tourism: "camp_site", name: "Zeltplatz" },
|
|
},
|
|
],
|
|
};
|
|
const categories = poiCategories.filter((c) => c.id === "camping");
|
|
const pois = parseResponse(data, categories);
|
|
|
|
expect(pois).toHaveLength(1);
|
|
expect(pois[0]!.lat).toBe(52.51);
|
|
expect(pois[0]!.lon).toBe(13.39);
|
|
});
|
|
|
|
it("skips elements without coordinates", () => {
|
|
const data = {
|
|
elements: [
|
|
{ type: "node", id: 789, tags: { amenity: "drinking_water" } },
|
|
],
|
|
};
|
|
const categories = poiCategories.filter((c) => c.id === "drinking_water");
|
|
const pois = parseResponse(data, categories);
|
|
expect(pois).toHaveLength(0);
|
|
});
|
|
|
|
it("skips elements that don't match any category", () => {
|
|
const data = {
|
|
elements: [
|
|
{ type: "node", id: 100, lat: 52.52, lon: 13.4, tags: { amenity: "bank" } },
|
|
],
|
|
};
|
|
const categories = poiCategories.filter((c) => c.id === "drinking_water");
|
|
const pois = parseResponse(data, categories);
|
|
expect(pois).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe("deduplicateById", () => {
|
|
it("removes duplicate POIs by id", () => {
|
|
const pois: Poi[] = [
|
|
{ id: 1, lat: 52.5, lon: 13.4, category: "drinking_water", tags: {} },
|
|
{ id: 1, lat: 52.5, lon: 13.4, category: "camping", tags: {} },
|
|
{ id: 2, lat: 52.6, lon: 13.5, category: "shelter", tags: {} },
|
|
];
|
|
const result = deduplicateById(pois);
|
|
expect(result).toHaveLength(2);
|
|
expect(result[0]!.id).toBe(1);
|
|
expect(result[1]!.id).toBe(2);
|
|
});
|
|
});
|