Files
localesp/tests/unit/resolverUbicacion.spec.js
T
edgar.friendly 003b1e209f
deploy-branch / deploy (push) Failing after 6s
deploy-branch / teardown (push) Skipped
feat(propuesta): pasarela paso a paso con autodetección de ubicación y FAB
- Campo universal de ubicación (Google Maps/Waze/OSM/coordenadas/dirección)
  sobre proveedores extensibles (src/utils/ubicacion) con resolver e inferencia
  inversa Nominatim (nombre/provincia pre-rellenados, alias cooficiales)
- FAB flotante abajo a la derecha que abre la pasarela en un modal accesible
  (Escape, foco contenido, responsive); sin descripción ni puntuación;
  avisos de duplicado y filtro de palabras dentro del modal
- Aviso PWA reposicionado: tarjeta abajo a la izquierda en móvil,
  botón compacto arriba a la izquierda en PC (no tapa el FAB)
- Suite de pruebas: 88 unitarias/componente (vitest + RTL, offline) y
  10 de integración (supertest + SQLite :memory: y Nominatim real opt-in)
- CI: workflow de Gitea Actions con npm test + build en push/PR e
  integración manual
2026-08-16 01:35:02 +02:00

91 lines
3.7 KiB
JavaScript

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();
}
});
});