import { afterEach, describe, expect, it, vi } from "vitest"; import { ETIQUETAS_PROVEEDOR, PROVEEDORES, inferirDesdeCoords, resolverUbicacion } from "../../src/utils/ubicacion/index.js"; afterEach(() => vi.unstubAllGlobals()); describe("resolverUbicacion", () => { it("respeta el orden de prioridad de PROVEEDORES (coordenadas → google → waze → osm → nominatim)", () => { expect(PROVEEDORES.map((p) => p.id)).toEqual(["coordenadas", "google-maps", "waze", "osm", "nominatim"]); }); it("resuelve un enlace de Google Maps sin tocar la red", async () => { const fetchMock = vi.fn(); vi.stubGlobal("fetch", fetchMock); const r = await resolverUbicacion("https://maps.google.com/@41.3851,2.1734,15z"); expect(r).toEqual({ proveedor: "google-maps", lat: 41.3851, lng: 2.1734 }); expect(fetchMock).not.toHaveBeenCalled(); }); it("resuelve coordenadas sueltas con el proveedor de coordenadas", async () => { const r = await resolverUbicacion("41.3851, 2.1734"); expect(r.proveedor).toBe("coordenadas"); }); it("hace fallback a Nominatim con texto de dirección (fetch simulado)", async () => { vi.stubGlobal("fetch", vi.fn(() => ({ ok: true, json: async () => [{ lat: "40.1", lon: "-3.2", display_name: "X, Madrid", address: { state: "Comunidad de Madrid" }, namedetails: {} }], }))); const r = await resolverUbicacion("Calle Mayor 5, Madrid"); expect(r.proveedor).toBe("nominatim"); expect(r.provincia).toBe("Madrid"); }); it("un proveedor que lanza se degrada y continúa con el siguiente", async () => { // se inyecta temporalmente un proveedor roto con máxima prioridad const roto = { id: "roto", detecta: () => true, extrae: async () => { throw new Error("boom"); } }; PROVEEDORES.unshift(roto); const error = vi.spyOn(console, "error").mockImplementation(() => {}); try { const r = await resolverUbicacion("https://maps.google.com/@41.3851,2.1734"); expect(r.proveedor).toBe("google-maps"); expect(error).toHaveBeenCalled(); } finally { PROVEEDORES.shift(); error.mockRestore(); } }); it("entrada no reconocida por nadie → null", async () => { expect(await resolverUbicacion("https://maps.app.goo.gl/abc123")).toBeNull(); expect(await resolverUbicacion("")).toBeNull(); expect(await resolverUbicacion(null)).toBeNull(); }); }); describe("inferirDesdeCoords", () => { it("usa el reverse de Nominatim y normaliza la provincia", async () => { const fetchMock = vi.fn(() => ({ ok: true, json: async () => ({ lat: "40.4168", lon: "-3.7038", display_name: "Puerta del Sol, Madrid, España", address: { state: "Comunidad de Madrid" }, namedetails: { name: "Puerta del Sol" }, }), })); vi.stubGlobal("fetch", fetchMock); const r = await inferirDesdeCoords(40.4168, -3.7038); expect(r).toEqual({ nombre: "Puerta del Sol", provincia: "Madrid", direccion: "Puerta del Sol, Madrid, España" }); const [url] = fetchMock.mock.calls[0]; expect(String(url)).toContain("/reverse"); expect(String(url)).toContain("addressdetails=1"); expect(String(url)).toContain("namedetails=1"); }); it("fallo de red → null sin lanzar", async () => { vi.stubGlobal("fetch", vi.fn(() => Promise.reject(new Error("sin red")))); const error = vi.spyOn(console, "error").mockImplementation(() => {}); expect(await inferirDesdeCoords(1, 1)).toBeNull(); error.mockRestore(); }); }); describe("ETIQUETAS_PROVEEDOR", () => { it("cubre todos los ids registrados (para los chips de la UI)", () => { for (const p of PROVEEDORES) { expect(ETIQUETAS_PROVEEDOR[p.id], `falta etiqueta para ${p.id}`).toBeTruthy(); } }); });