/** * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * Project: Groupe Ka / Ka Maps */ import { describe, expect, it } from "vitest"; import { computeLensStats, propertiesInBBox, propertiesInPolygon, } from "../src/utils/lens.js"; import type { MapProperty } from "../src/types/index.js"; function prop(over: Partial): MapProperty { return { id: over.id ?? Math.random().toString(36), appSource: "lou-ka", latitude: 46.8, longitude: -71.2, kind: "listing", ...over, }; } describe("computeLensStats", () => { it("computes medians and type mix from real fields only", () => { const stats = computeLensStats([ prop({ price: 300_000, propertyType: "Maison", daysOnMarket: 10 }), prop({ price: 500_000, propertyType: "Maison", daysOnMarket: 100 }), prop({ price: 700_000, propertyType: "Condo", priceChange: -0.05 }), ]); expect(stats.count).toBe(3); expect(stats.medianPrice).toBe(500_000); expect(stats.medianDaysOnMarket).toBe(55); expect(stats.stale90dShare).toBe(0.5); expect(stats.priceCutShare).toBeCloseTo(1 / 3); expect(stats.typeMix?.["Maison"]).toBeCloseTo(2 / 3); // pas de valeurs estimées dans les données → pas de médiane inventée expect(stats.medianEstimatedValue).toBeUndefined(); }); it("returns bare count on empty/opaque data", () => { const stats = computeLensStats([]); expect(stats).toEqual({ count: 0 }); }); }); describe("geographic selection", () => { const items = [ prop({ id: "in", latitude: 46.8, longitude: -71.2 }), prop({ id: "out", latitude: 45.5, longitude: -73.6 }), ]; it("filters by bbox", () => { const sel = propertiesInBBox(items, { west: -71.4, south: 46.7, east: -71.0, north: 46.9, }); expect(sel.map((p) => p.id)).toEqual(["in"]); }); it("filters by polygon (ray casting)", () => { const sel = propertiesInPolygon(items, { type: "Polygon", coordinates: [[[-71.4, 46.7], [-71.0, 46.7], [-71.0, 46.9], [-71.4, 46.9], [-71.4, 46.7]]], }); expect(sel.map((p) => p.id)).toEqual(["in"]); }); });