import { describe, expect, it } from "vitest"; import { normalizeMarineForecast } from "../src/services/weather.js"; describe("departure-time marine forecast", () => { it("selects waves, wind and ocean current nearest the requested passage time", () => { const result = normalizeMarineForecast( { hourly: { time: ["2026-07-20T08:00", "2026-07-20T09:00"], wave_height: [0.6, 0.9], wave_direction: [280, 290], wave_period: [4, 5], ocean_current_velocity: [0.4, 1.1], ocean_current_direction: [90, 100], sea_level_height_msl: [0.2, 0.4] } }, { hourly: { time: ["2026-07-20T08:00", "2026-07-20T09:00"], wind_speed_10m: [8, 12], wind_direction_10m: [240, 250], weather_code: [2, 3], temperature_2m: [18, 19] } }, { marineAvailable: true, weatherAvailable: true }, "2026-07-20T08:40:00.000Z" ); expect(result).toMatchObject({ waveHeightM: 0.9, windSpeed: 12, oceanCurrentSpeedKn: 1.1, oceanCurrentDirectionDeg: 100, seaLevelHeightMslM: 0.4, forecastTime: "2026-07-20T09:00:00.000Z" }); }); it("does not reuse the edge of the forecast as if it covered a much later departure", () => { const result = normalizeMarineForecast( { hourly: { time: ["2026-07-20T08:00"], wave_height: [0.6], wave_direction: [280], wave_period: [4], ocean_current_velocity: [0.4], ocean_current_direction: [90], sea_level_height_msl: [0.2] } }, { hourly: { time: ["2026-07-20T08:00"], wind_speed_10m: [8], wind_direction_10m: [240], weather_code: [2], temperature_2m: [18] } }, { marineAvailable: true, weatherAvailable: true }, "2026-07-24T08:00:00.000Z" ); expect(result).toMatchObject({ waveHeightM: null, windSpeed: null, oceanCurrentSpeedKn: null, oceanCurrentDirectionDeg: null }); }); });