Files
watermaps/apps/web/tests/route-weather-report.test.ts
T
BuTzZ b98ec8bc6f
Test and publish container images / test (push) Successful in 2m27s
Test and publish container images / publish (push) Failing after 4s
Hinweise optimiert
2026-07-27 13:04:32 +02:00

169 lines
5.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { MarineForecast, RouteResult } from "@watermaps/shared";
import { createRouteWeatherReport, summarizeRouteWeather } from "../src/routeWeatherReport";
describe("route weather report", () => {
it("samples start, middle and destination forecasts", async () => {
const requested: Array<{ lat: number; lon: number }> = [];
const report = await createRouteWeatherReport(routeFixture, async (coordinate) => {
requested.push(coordinate);
return forecast({
windSpeed: coordinate.lon > 7.1 ? 18 : 10,
waveHeightM: coordinate.lon > 7.1 ? 1.2 : 0.4
});
});
expect(requested).toHaveLength(3);
expect(report.maxWindSpeedKn).toBe(18);
expect(report.maxWaveHeightM).toBe(1.2);
expect(report.severity).toBe("caution");
expect(report.summary).toContain("Aufmerksam fahren");
expect(report.bridgeReport).toBeNull();
});
it("projects forecasts along the route timeline and adjusts ETA for along-route current", async () => {
const requestedTimes: Array<string | undefined> = [];
const departureTime = "2026-07-20T06:00:00.000Z";
const timedRoute: RouteResult = {
...routeFixture,
geometry: {
type: "LineString",
coordinates: [[7, 52], [7.2, 52], [7.4, 52]]
},
distanceNm: 20,
departureTime,
durationMinutes: 240,
eta: "2026-07-20T10:00:00.000Z"
};
const report = await createRouteWeatherReport(
timedRoute,
{ draughtM: 1.4, safetyReserveM: 0.5, cruiseSpeedKn: 5 },
async (_coordinate, at) => {
requestedTimes.push(at);
return forecast({
oceanCurrentSpeedKn: 1,
oceanCurrentDirectionDeg: 90,
forecastTime: at
});
}
);
expect(requestedTimes).toEqual([
"2026-07-20T06:00:00.000Z",
"2026-07-20T08:00:00.000Z",
"2026-07-20T10:00:00.000Z"
]);
expect(report.samples.map((sample) => sample.plannedTime)).toEqual(requestedTimes);
expect(report.samples.map((sample) => sample.currentAlongRouteKn)).toEqual([1, 1, 1]);
expect(report.departureTime).toBe(departureTime);
expect(report.averageAlongRouteCurrentKn).toBe(1);
expect(report.currentAdjustmentMinutes).toBe(-40);
expect(report.adjustedEta).toBe("2026-07-20T09:20:00.000Z");
});
it("adds a bridge report and marks a route as blocked by a low bridge", async () => {
const report = await createRouteWeatherReport(
routeFixture,
{ draughtM: 1.4, safetyReserveM: 0.5, airDraftM: 3 },
async () => forecast({}),
async (params) => {
expect(params.layers).toEqual(["bridges"]);
return {
type: "FeatureCollection",
features: [
{
type: "Feature",
id: "bridge-low",
properties: {
layer: "bridges",
name: "Niedrige Brücke",
clearance_m: 2.7,
clearance_label: "H 2.7 m",
label: "Niedrige Brücke H 2.7 m",
source: "OSM/Geofabrik"
},
geometry: {
type: "LineString",
coordinates: [
[6.99, 53.5],
[7.21, 53.5]
]
}
},
{
type: "Feature",
id: "bridge-high",
properties: {
layer: "bridges",
name: "Hohe Brücke",
clearance_m: 4.2,
clearance_label: "H 4.2 m",
label: "Hohe Brücke H 4.2 m",
source: "OSM/Geofabrik"
},
geometry: {
type: "LineString",
coordinates: [
[7.18, 53.68],
[7.22, 53.68]
]
}
}
]
};
}
);
expect(report.bridgeReport?.severity).toBe("critical");
expect(report.bridgeReport?.tooLowCount).toBe(1);
expect(report.bridgeReport?.checkedCount).toBe(2);
expect(report.bridgeReport?.summary).toContain("Nicht passierbar");
expect(report.bridgeReport?.bridges[0]?.name).toBe("Niedrige Brücke");
});
it("marks critical weather when wind or wave thresholds are exceeded", () => {
const report = summarizeRouteWeather([
{
label: "Mitte",
coordinate: { lat: 53.5, lon: 7.1 },
forecast: forecast({ windSpeed: 28, waveHeightM: 1.1 })
}
]);
expect(report.severity).toBe("critical");
expect(report.summary).toContain("Kritische Bedingungen");
});
});
const routeFixture: RouteResult = {
geometry: {
type: "LineString",
coordinates: [
[7, 53.3],
[7.1, 53.5],
[7.2, 53.7]
]
},
distanceNm: 25,
eta: null,
warnings: [],
dataSources: [],
routingMode: "fairway"
};
function forecast(overrides: Partial<MarineForecast>): MarineForecast {
return {
waveHeightM: 0.4,
waveDirectionDeg: 280,
wavePeriodS: 4,
windSpeed: 10,
windDirectionDeg: 260,
weatherCode: 2,
temperatureC: 18,
source: "Test",
updatedAt: "2026-07-13T12:00:00.000Z",
...overrides
};
}