- 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
93 lines
3.6 KiB
JavaScript
93 lines
3.6 KiB
JavaScript
import { beforeAll, describe, expect, it } from "vitest";
|
|
import request from "supertest";
|
|
|
|
// BD en memoria: aislada, offline y determinista. Debe configurarse ANTES de
|
|
// importar la app (server/db.js resuelve la ruta en la carga del módulo).
|
|
process.env.LOCALESP_DB = ":memory:";
|
|
|
|
let app;
|
|
beforeAll(async () => {
|
|
({ default: app } = await import("../../server/index.js"));
|
|
});
|
|
|
|
// Payload equivalente al que envía la pasarela tras este cambio: sin
|
|
// descripcion y sin puntuacion (el backend aplica sus defaults).
|
|
const PROPUESTA_PASARELA = {
|
|
nombre: "Bar El Olivo",
|
|
provincia: "Madrid",
|
|
categoria: "Restauración",
|
|
subcategoria: "Tapas y raciones",
|
|
direccion: "Calle Mayor 5, Alcalá de Henares",
|
|
enlaceGoogleMaps: "",
|
|
lat: 40.4828,
|
|
lng: -3.3652,
|
|
};
|
|
|
|
describe("Integración API local (Express + SQLite en memoria)", () => {
|
|
it("GET /api/locales arranca limpio", async () => {
|
|
const r = await request(app).get("/api/locales");
|
|
expect(r.status).toBe(200);
|
|
expect(r.body).toEqual([]);
|
|
});
|
|
|
|
it("POST /api/propuestas acepta una propuesta de la pasarela sin descripcion ni puntuacion (defaults)", async () => {
|
|
const r = await request(app).post("/api/propuestas").send(PROPUESTA_PASARELA);
|
|
expect(r.status).toBe(201);
|
|
expect(r.body.nombre).toBe("Bar El Olivo");
|
|
expect(r.body.puntuacion).toBe(0); // default del backend
|
|
expect(r.body.estado).toBe("pendiente");
|
|
expect(r.body.id).toBeTruthy();
|
|
|
|
// y aparece en pendientes (vista admin)
|
|
const pend = await request(app).get("/api/pendientes");
|
|
expect(pend.body.map((p) => p.nombre)).toContain("Bar El Olivo");
|
|
});
|
|
|
|
it("POST /api/check-duplicado detecta mismo nombre normalizado en la misma provincia", async () => {
|
|
const r = await request(app)
|
|
.post("/api/check-duplicado")
|
|
.send({ nombre: "bar el olivo", provincia: "Madrid", lat: 41.0, lng: -4.0 }); // lejos: cuenta la provincia
|
|
expect(r.body.duplicado).toBe(true);
|
|
expect(r.body.coincidencias[0]).toMatchObject({
|
|
nombre: "Bar El Olivo",
|
|
provincia: "Madrid",
|
|
estado: "pendiente", // aún no publicado
|
|
});
|
|
});
|
|
|
|
it("POST /api/check-duplicado detecta por cercanía aunque cambie la provincia", async () => {
|
|
const r = await request(app)
|
|
.post("/api/check-duplicado")
|
|
.send({ nombre: "BAR EL OLIVO", provincia: "Barcelona", lat: 40.48281, lng: -3.36521 }); // ~1-2 m
|
|
expect(r.body.duplicado).toBe(true);
|
|
});
|
|
|
|
it("POST /api/check-duplicado no marca nombres distintos ni mismos nombres lejos y en otra provincia", async () => {
|
|
const distinto = await request(app)
|
|
.post("/api/check-duplicado")
|
|
.send({ nombre: "Cafetería Luna", provincia: "Madrid", lat: 40.48, lng: -3.36 });
|
|
expect(distinto.body.duplicado).toBe(false);
|
|
|
|
const lejosOtraProvincia = await request(app)
|
|
.post("/api/check-duplicado")
|
|
.send({ nombre: "Bar El Olivo", provincia: "Sevilla", lat: 37.38, lng: -5.98 });
|
|
expect(lejosOtraProvincia.body.duplicado).toBe(false);
|
|
});
|
|
|
|
it("flujo admin completo: aprobar publica el local con los datos de la propuesta", async () => {
|
|
const propuesta = (await request(app).get("/api/pendientes")).body[0];
|
|
const aprobado = await request(app).post(`/api/aprobar/${propuesta.id}`);
|
|
expect(aprobado.body.ok).toBe(true);
|
|
|
|
const locales = (await request(app).get("/api/locales")).body;
|
|
const publicado = locales.find((l) => l.nombre === "Bar El Olivo");
|
|
expect(publicado).toMatchObject({
|
|
provincia: "Madrid",
|
|
categoria: "Restauración",
|
|
subcategoria: "Tapas y raciones",
|
|
direccion: "Calle Mayor 5, Alcalá de Henares",
|
|
puntuacion: 0, // default aplicado en cascada
|
|
});
|
|
});
|
|
});
|