diff --git a/front/src/pods/embalse-search/embalse-search.mapper.spec.ts b/front/src/pods/embalse-search/embalse-search.mapper.spec.ts new file mode 100644 index 0000000..5fc85f2 --- /dev/null +++ b/front/src/pods/embalse-search/embalse-search.mapper.spec.ts @@ -0,0 +1,80 @@ +import { describe, it, expect } from "vitest"; +import { mapEmbalseToSearch } from "./embalse-search.mapper"; +import type { Embalse } from "db-model"; + +describe("mapEmbalseToSearch", () => { + it("should map embalse to search model correctly", () => { + const mockEmbalse: Embalse = { + _id: "test-id-123", + nombre: "Albarracín", + provincia: "Teruel", + } as Embalse; + + const result = mapEmbalseToSearch(mockEmbalse); + + expect(result).toEqual({ + slug: "test-id-123", + name: "Albarracín (Teruel)", + }); + }); + + it("should handle empty province", () => { + const mockEmbalse: Embalse = { + _id: "test-id-456", + nombre: "Embalse Test", + provincia: "", + } as Embalse; + + const result = mapEmbalseToSearch(mockEmbalse); + + expect(result).toEqual({ + slug: "test-id-456", + name: "Embalse Test ()", + }); + }); + + it("should handle null province", () => { + const mockEmbalse: Embalse = { + _id: "test-id-789", + nombre: "Embalse Test", + provincia: null, + } as Embalse; + + const result = mapEmbalseToSearch(mockEmbalse); + + expect(result).toEqual({ + slug: "test-id-789", + name: "Embalse Test (null)", + }); + }); + + it("should handle special characters in name and province", () => { + const mockEmbalse: Embalse = { + _id: "test-id-special", + nombre: "Cueva de la Mora", + provincia: "Huelva", + } as Embalse; + + const result = mapEmbalseToSearch(mockEmbalse); + + expect(result).toEqual({ + slug: "test-id-special", + name: "Cueva de la Mora (Huelva)", + }); + }); + + it("should handle numeric ID", () => { + const mockEmbalse: Embalse = { + _id: "12345", + nombre: "La Viñuela", + provincia: "Málaga", + } as Embalse; + + const result = mapEmbalseToSearch(mockEmbalse); + + expect(result).toEqual({ + slug: "12345", + name: "La Viñuela (Málaga)", + }); + }); +}); \ No newline at end of file diff --git a/front/src/pods/embalse/embalse.mapper.spec.ts b/front/src/pods/embalse/embalse.mapper.spec.ts new file mode 100644 index 0000000..51d4561 --- /dev/null +++ b/front/src/pods/embalse/embalse.mapper.spec.ts @@ -0,0 +1,194 @@ +import { describe, it, expect } from "vitest"; +import { mapEmbalseToReservoirData } from "./embalse.mapper"; +import type { Embalse } from "db-model"; + +describe("mapEmbalseToReservoirData", () => { + const mockEmbalseBase: Partial = { + _id: "test-id", + nombre: "Albarracín", + capacidad: 1000, + provincia: "Teruel", + cuenca: { nombre: "Júcar", _id: "cuenca-id" }, + }; + + it("should prioritize SAIH data over AEMET when both are available", () => { + // Arrange + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + aguaActualSAIH: 800, + fechaMedidaAguaActualSAIH: new Date("2024-01-15"), + aguaActualAemet: 600, + fechaMedidaAguaActualAemet: new Date("2024-01-10"), + } as Embalse; + + // Act + const result = mapEmbalseToReservoirData(mockEmbalse); + + // Assert + expect(result.currentVolume).toBe(800); + expect(result.measurementDate).toBe("15/01/2024"); + }); + + it("should use AEMET data when SAIH is null", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + aguaActualSAIH: null, + fechaMedidaAguaActualSAIH: null, + aguaActualAemet: 600, + fechaMedidaAguaActualAemet: new Date("2024-01-10"), + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.currentVolume).toBe(600); + expect(result.measurementDate).toBe("10/01/2024"); + }); + + it("should set currentVolume to 0 when both water measurements are null", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + aguaActualSAIH: null, + fechaMedidaAguaActualSAIH: null, + aguaActualAemet: null, + fechaMedidaAguaActualAemet: null, + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.currentVolume).toBe(0); + expect(result.measurementDate).toBe(""); + }); + + it("should format date correctly from Date object", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + aguaActualSAIH: 500, + fechaMedidaAguaActualSAIH: new Date("2024-12-25"), + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.measurementDate).toBe("25/12/2024"); + }); + + it("should format date correctly from string", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + aguaActualSAIH: 500, + fechaMedidaAguaActualSAIH: new Date("2024-12-25T10:30:00Z"), + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.measurementDate).toBe("25/12/2024"); + }); + + it("should handle invalid date string", () => { + const mockEmbalse = { + ...mockEmbalseBase, + aguaActualSAIH: 500, + fechaMedidaAguaActualSAIH: "invalid-date", + } as unknown as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.measurementDate).toBe(""); + }); + + it("should handle null/undefined dates", () => { + const testCases = [ + { fecha: null, description: "null date" }, + { fecha: undefined, description: "undefined date" }, + ]; + + testCases.forEach(({ fecha, description }) => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + aguaActualSAIH: 500, + fechaMedidaAguaActualSAIH: fecha, + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + expect(result.measurementDate).toBe(``); + }); + }); + + it("should map cuenca correctly when cuenca exists", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + cuenca: { nombre: "Tajo" }, + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.datosEmbalse.cuenca).toBe("Tajo"); + }); + + it("should handle null cuenca", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + cuenca: null, + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.datosEmbalse.cuenca).toBe(""); + }); + + it("should handle missing cuenca", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + } as Embalse; + delete (mockEmbalse as any).cuenca; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.datosEmbalse.cuenca).toBe(""); + }); + + it("should map all fields correctly", () => { + const mockEmbalse: Embalse = { + _id: "test-id", + nombre: "La Viñuela", + capacidad: 1500, + aguaActualSAIH: 750, + fechaMedidaAguaActualSAIH: new Date("2024-06-15"), + provincia: "Málaga", + cuenca: { nombre: "Mediterránea" }, + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result).toEqual({ + nombre: "La Viñuela", + currentVolume: 750, + totalCapacity: 1500, + measurementDate: "15/06/2024", + datosEmbalse: { + cuenca: "Mediterránea", + provincia: "Málaga", + municipio: "", + rio: "", + embalsesAguasAbajo: 0, + tipoDePresa: "", + anioConstruccion: 0, + superficie: 0, + localizacion: "", + }, + reservoirInfo: { + Description: "", + }, + }); + }); + + it("should handle missing provincia", () => { + const mockEmbalse: Embalse = { + ...mockEmbalseBase, + provincia: null, + } as Embalse; + + const result = mapEmbalseToReservoirData(mockEmbalse); + + expect(result.datosEmbalse.provincia).toBe(""); + }); +}); diff --git a/front/src/pods/embalse/embalse.repository.mapper.spec.ts b/front/src/pods/embalse/embalse.repository.mapper.spec.ts new file mode 100644 index 0000000..128b094 --- /dev/null +++ b/front/src/pods/embalse/embalse.repository.mapper.spec.ts @@ -0,0 +1,215 @@ +import { describe, it, expect } from "vitest"; +import { mapEmbalse } from "./embalse.repository.mapper"; +import { createEmptyEmbalse } from "./embalse.vm"; +import type { Embalse } from "db-model"; + +describe("embalse repository mapper specs", () => { + it.each<{ embalse: Embalse | null | undefined }>([ + { embalse: undefined }, + { embalse: null }, + ])( + "should return empty embalse when it feeds embalse equals $embalse", + ({ embalse }) => { + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result).toEqual(createEmptyEmbalse()); + } + ); + + it("should throw error when _id is undefined", () => { + // Arrange + const embalse = { + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: { _id: "test-id", nombre: "Test Cuenca" }, + capacidad: 1000, + } as Embalse; + + // Act & Assert + expect(() => mapEmbalse(embalse)).toThrow("Cannot read properties of undefined"); + }); + + it("should return mapped embalse when it feeds valid embalse with all fields", () => { + // Arrange + const embalse: Embalse = { + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "La Viñuela", + slug: "la-vinuela", + cuenca: { _id: "507f1f77bcf86cd799439012", nombre: "Mediterránea" }, + provincia: "Málaga", + capacidad: 1500, + aguaActualAemet: 750, + fechaMedidaAguaActualAemet: new Date("2024-01-15"), + aguaActualSAIH: 800, + fechaMedidaAguaActualSAIH: new Date("2024-01-16"), + descripcion_id: "456", + uso: "Riego", + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result).toEqual({ + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "La Viñuela", + slug: "la-vinuela", + cuenca: { + _id: "507f1f77bcf86cd799439012", + nombre: "Mediterránea", + }, + provincia: "Málaga", + capacidad: 1500, + aguaActualAemet: 750, + fechaMedidaAguaActualAemet: new Date("2024-01-15"), + aguaActualSAIH: 800, + fechaMedidaAguaActualSAIH: new Date("2024-01-16"), + descripcion_id: "456", + uso: "Riego", + }); + }); + + it("should map embalse with null cuenca correctly", () => { + // Arrange + const embalse: Embalse = { + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: null, + provincia: "Test Province", + capacidad: 1000, + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result.cuenca).toEqual({ + _id: "", + nombre: "", + }); + }); + + it("should map embalse with undefined cuenca _id correctly", () => { + // Arrange + const embalse: Embalse = { + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: { nombre: "Test Cuenca" }, + provincia: "Test Province", + capacidad: 1000, + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result.cuenca).toEqual({ + _id: "", + nombre: "Test Cuenca", + }); + }); + + it("should map embalse with undefined cuenca nombre correctly", () => { + // Arrange + const embalse: Embalse = { + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: { _id: "507f1f77bcf86cd799439012" }, + provincia: "Test Province", + capacidad: 1000, + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result.cuenca).toEqual({ + _id: "507f1f77bcf86cd799439012", + nombre: "", + }); + }); + + it("should convert _id to string", () => { + // Arrange + const embalse: Embalse = { + _id: { toString: () => "507f1f77bcf86cd799439011" } as any, + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: { _id: "507f1f77bcf86cd799439012", nombre: "Test Cuenca" }, + capacidad: 1000, + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result._id).toBe("507f1f77bcf86cd799439011"); + }); + + it("should handle null optional fields correctly", () => { + // Arrange + const embalse: Embalse = { + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: { _id: "507f1f77bcf86cd799439012", nombre: "Test Cuenca" }, + provincia: null, + capacidad: 1000, + aguaActualAemet: null, + fechaMedidaAguaActualAemet: null, + aguaActualSAIH: null, + fechaMedidaAguaActualSAIH: null, + descripcion_id: null, + uso: null, + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result.provincia).toBeNull(); + expect(result.aguaActualAemet).toBeNull(); + expect(result.fechaMedidaAguaActualAemet).toBeNull(); + expect(result.aguaActualSAIH).toBeNull(); + expect(result.fechaMedidaAguaActualSAIH).toBeNull(); + expect(result.descripcion_id).toBeNull(); + expect(result.uso).toBe(""); + }); + + it("should convert undefined optional fields to defaults", () => { + // Arrange + const embalse: Embalse = { + _id: "507f1f77bcf86cd799439011", + embalse_id: 123, + nombre: "Test Embalse", + slug: "test-embalse", + cuenca: { _id: "507f1f77bcf86cd799439012", nombre: "Test Cuenca" }, + capacidad: 1000, + } as Embalse; + + // Act + const result = mapEmbalse(embalse); + + // Assert + expect(result.provincia).toBeNull(); + expect(result.aguaActualAemet).toBeNull(); + expect(result.fechaMedidaAguaActualAemet).toBeNull(); + expect(result.aguaActualSAIH).toBeNull(); + expect(result.fechaMedidaAguaActualSAIH).toBeNull(); + expect(result.descripcion_id).toBeNull(); + expect(result.uso).toBe(""); + }); +}); \ No newline at end of file diff --git a/front/src/pods/embalse/embalse.repository.mapper.ts b/front/src/pods/embalse/embalse.repository.mapper.ts new file mode 100644 index 0000000..aab4813 --- /dev/null +++ b/front/src/pods/embalse/embalse.repository.mapper.ts @@ -0,0 +1,24 @@ +import type { Embalse } from "db-model"; +import { createEmptyEmbalse } from "./embalse.vm"; + +export const mapEmbalse = (embalse: Embalse) => + Boolean(embalse) + ? { + _id: embalse._id.toString(), + embalse_id: embalse.embalse_id, + nombre: embalse.nombre, + slug: embalse.slug, + cuenca: { + _id: embalse.cuenca?._id?.toString() ?? "", + nombre: embalse.cuenca?.nombre ?? "", + }, + provincia: embalse.provincia ?? null, + capacidad: embalse.capacidad, + aguaActualAemet: embalse.aguaActualAemet ?? null, + fechaMedidaAguaActualAemet: embalse.fechaMedidaAguaActualAemet ?? null, + aguaActualSAIH: embalse.aguaActualSAIH ?? null, + fechaMedidaAguaActualSAIH: embalse.fechaMedidaAguaActualSAIH ?? null, + descripcion_id: embalse.descripcion_id ?? null, + uso: embalse.uso ?? "", + } + : createEmptyEmbalse(); diff --git a/front/src/pods/embalse/embalse.repository.ts b/front/src/pods/embalse/embalse.repository.ts index fbf70aa..6e3ec70 100644 --- a/front/src/pods/embalse/embalse.repository.ts +++ b/front/src/pods/embalse/embalse.repository.ts @@ -2,32 +2,16 @@ import { getDb } from "@/lib/mongodb"; import type { Embalse } from "db-model"; - +import { mapEmbalse } from "./embalse.repository.mapper"; export async function getEmbalseBySlug(slug: string): Promise { - //conecta con BD y trae datos en base al slug + //conecta con BD y trae datos en base al slug const db = await getDb(); - const doc = await db.collection("embalses").findOne({ slug }); + const embalse = await db.collection("embalses").findOne({ slug }); - if (!doc) { + if (!embalse) { return null; } - //mapea el resultado de la BD al tipo Embalse y nos aseguramos de que lleven los tipos correctos (tienen que ser primitivos) - return { - _id: doc._id.toString(), - embalse_id: doc.embalse_id, - nombre: doc.nombre, - slug: doc.slug, - cuenca: { - _id: doc.cuenca?._id?.toString() ?? "", - nombre: doc.cuenca?.nombre ?? "", - }, - provincia: doc.provincia ?? null, - capacidad: doc.capacidad, - aguaActualAemet: doc.aguaActualAemet ?? null, - fechaMedidaAguaActualAemet: doc.fechaMedidaAguaActualAemet ?? null, - aguaActualSAIH: doc.aguaActualSAIH ?? null, - fechaMedidaAguaActualSAIH: doc.fechaMedidaAguaActualSAIH ?? null, - descripcion_id: doc.descripcion_id ?? null, - uso: doc.uso ?? "", - }; + + const mappedEmbalse = mapEmbalse(embalse); + return mappedEmbalse; } diff --git a/front/src/pods/embalse/embalse.vm.ts b/front/src/pods/embalse/embalse.vm.ts index 7e7b598..c6ef6af 100644 --- a/front/src/pods/embalse/embalse.vm.ts +++ b/front/src/pods/embalse/embalse.vm.ts @@ -1,3 +1,5 @@ +import type { Embalse } from "db-model"; + export interface DatosEmbalse { cuenca: string; provincia: string; @@ -22,3 +24,19 @@ export interface ReservoirData { datosEmbalse: DatosEmbalse; reservoirInfo: ReservoirInfo; } + +export const createEmptyEmbalse = (): Embalse => ({ + _id: "", + embalse_id: 0, + nombre: "", + slug: "", + cuenca: { _id: "", nombre: "" }, + provincia: null, + capacidad: 0, + aguaActualAemet: null, + fechaMedidaAguaActualAemet: null, + aguaActualSAIH: null, + fechaMedidaAguaActualSAIH: null, + descripcion_id: null, + uso: "", +});