import { describe, expect, it } from "vitest"; import { estimate, adjustComps, timeFactor, weightedMedian, haversineM, type CompInput } from "../src/lib/engine"; const index = [{ month: "2025-01", idx: 0.9 }, { month: "2025-07", idx: 0.95 }, { month: "2026-01", idx: 1.0 }]; const mk = (i: number, amount: number, dLat = 0, area = 150, year = 2000): CompInput => ({ id: `t${i}`, date: "2025-07-15", amount, lat: 46.8 + dLat, lng: -71.2, propertyType: "unifamilial", yearBuilt: year, floorArea: area, street: `${i} rue Test`, city: "Québec" }); describe("moteur d'estimation (copie Vrai-Prix)", () => { it("facteur temps = indice courant / indice au mois de vente", () => { expect(timeFactor("2025-01", index)).toBeCloseTo(1 / 0.9); expect(timeFactor("2026-03", index)).toBe(1); }); it("médiane pondérée", () => { expect(weightedMedian([100, 200, 300], [1, 1, 1])).toBe(200); expect(weightedMedian([100, 200, 300], [10, 1, 1])).toBe(100); }); it("haversine", () => { expect(Math.round(haversineM(46.8, -71.2, 46.81, -71.2))).toBeGreaterThan(1100); }); it("ajuste et pondère les comparables ; hors type relâché si marché mince", () => { const comps = adjustComps({ lat: 46.8, lng: -71.2, typeProp: "unifamilial", floorArea: 150, yearBuilt: 2000 }, Array.from({ length: 10 }, (_, i) => mk(i, 400000 + i * 1000, i * 0.001)), index, "2026-01-15"); expect(comps.length).toBe(10); expect(comps[0].distanceM).toBeLessThan(comps[9].distanceM); expect(comps[0].adjTime).toBeCloseTo(400000 * (1 / 0.95 - 1), 0); }); it("mélange modèle 65 % / comparables 35 % et borne la confiance", () => { const r = estimate({ lat: 46.8, lng: -71.2, typeProp: "unifamilial", floorArea: 150, yearBuilt: 2000, modelEstimate: 450000, modelP10: 400000, modelP90: 500000 }, Array.from({ length: 12 }, (_, i) => mk(i, 400000, i * 0.0005)), index, "2026-01-15"); expect(r.modelWeight).toBe(0.65); expect(r.estimate).toBeGreaterThan(420000); expect(r.estimate).toBeLessThan(450000); expect(r.low).toBeLessThan(r.estimate); expect(r.high).toBeGreaterThan(r.estimate); expect(r.confidencePct).toBeGreaterThanOrEqual(5); expect(r.confidencePct).toBeLessThanOrEqual(97); expect(["A", "B", "C", "D"]).toContain(r.confidenceLevel); }); it("sans modèle ni comparables → NaN (jamais une valeur inventée)", () => { expect(Number.isNaN(estimate({ lat: 46.8, lng: -71.2, typeProp: "unifamilial" }, [], index, "2026-01-15").estimate)).toBe(true); }); });