Files
watermaps/apps/web/tests/upcoming-events-panel.test.tsx
T
BuTzZ 593dbd5f85
Test and publish container images / test (push) Successful in 2m26s
Test and publish container images / publish (push) Failing after 3s
optimized events
2026-07-28 14:36:47 +02:00

208 lines
6.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import "@testing-library/jest-dom/vitest";
import { cleanup, fireEvent, render, screen, within } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { UpcomingRouteEvent } from "../src/routeEvents";
import { UpcomingEventsPanel } from "../src/components/UpcomingEventsPanel";
afterEach(cleanup);
describe("UpcomingEventsPanel", () => {
it("shows the nearest event first, preserves chronological list order and filters by kind", () => {
render(<UpcomingEventsPanel events={events} hasRoute />);
const hero = screen.getByText("Nächstes Ereignis").closest("article");
expect(hero).not.toBeNull();
expect(within(hero!).getByText("Schleuse Nah")).toBeVisible();
expect(within(hero!).getByText("3,0 sm")).toBeVisible();
expect(within(hero!).getByText(/ETA/)).toBeVisible();
const list = screen.getByRole("list");
expect(
within(list)
.getAllByRole("button")
.map((button) => button.textContent)
).toEqual([
expect.stringContaining("Schleuse Nah"),
expect.stringContaining("Brücke Mitte"),
expect.stringContaining("Hafen Weit")
]);
expect(within(list).getAllByText("Infos")).toHaveLength(3);
fireEvent.click(screen.getByRole("button", { name: /Brücken/ }));
expect(screen.getByRole("button", { name: /Brücken/ })).toHaveAttribute(
"aria-pressed",
"true"
);
expect(screen.getAllByText("Brücke Mitte")).toHaveLength(2);
expect(screen.queryByText("Schleuse Nah")).not.toBeInTheDocument();
expect(screen.queryByText("Hafen Weit")).not.toBeInTheDocument();
expect(within(screen.getByRole("list")).getAllByRole("button")).toHaveLength(1);
});
it("opens a lock drilldown with direct contact, VHF, hours and map actions", () => {
const onShowOnMap = vi.fn();
render(
<UpcomingEventsPanel
events={events}
hasRoute
onShowOnMap={onShowOnMap}
/>
);
const hero = screen.getByText("Nächstes Ereignis").closest("article");
fireEvent.click(within(hero!).getByRole("button", { name: /Schleuse Nah/ }));
const detail = screen.getByRole("region", { name: "Schleuse Nah" });
expect(within(detail).getByText("MoFr 08:0018:00")).toBeVisible();
expect(within(detail).getByText("Kanal 12")).toBeVisible();
expect(within(detail).getByRole("link", { name: "Schleuse Nah anrufen" })).toHaveAttribute(
"href",
"tel:+4949123456"
);
expect(
within(detail).getByRole("link", { name: "Website von Schleuse Nah öffnen" })
).toHaveAttribute("href", "https://lock.example/");
fireEvent.click(within(detail).getByRole("button", { name: "Auf Karte zeigen" }));
expect(onShowOnMap).toHaveBeenCalledWith(events[0]);
fireEvent.click(within(detail).getByRole("button", { name: "Zurück zur Ereignisliste" }));
expect(screen.getByText("Nächstes Ereignis")).toBeVisible();
});
it("shows bridge clearance, required height and reserve in its drilldown", () => {
render(<UpcomingEventsPanel events={events} hasRoute />);
fireEvent.click(screen.getByRole("button", { name: /Brücken/ }));
const hero = screen.getByText("Nächstes Ereignis").closest("article");
fireEvent.click(within(hero!).getByRole("button", { name: /Brücke Mitte/ }));
const detail = screen.getByRole("region", { name: "Brücke Mitte" });
expect(within(detail).getByText("H 4,2 m")).toBeVisible();
expect(within(detail).getByText("3.8 m")).toBeVisible();
const reserve = within(detail).getByText("Reserve").closest("div");
expect(reserve).toHaveTextContent("0.4 m Reserve");
expect(
within(detail).getByRole("link", { name: "Brücke Mitte anrufen" })
).toHaveAttribute("href", "tel:+4949123457");
expect(
within(detail).getByRole("link", { name: "Website von Brücke Mitte öffnen" })
).toHaveAttribute("href", "https://bridge.example/");
expect(within(detail).queryByRole("button", { name: "Auf Karte zeigen" })).not.toBeInTheDocument();
});
it.each([
{
props: { hasRoute: false, events: [] as UpcomingRouteEvent[] },
text: "Noch keine Route",
role: undefined
},
{
props: { hasRoute: true, events: [] as UpcomingRouteEvent[], loading: true },
text: "Ereignisse werden geladen",
role: "status"
},
{
props: {
hasRoute: true,
events: [] as UpcomingRouteEvent[],
error: "Datenquelle antwortet nicht"
},
text: "Ereignisse nicht erreichbar",
role: "alert"
},
{
props: { hasRoute: true, events: [] as UpcomingRouteEvent[] },
text: "Keine bevorstehenden Ereignisse",
role: undefined
}
])("renders the state '$text'", ({ props, text, role }) => {
render(<UpcomingEventsPanel {...props} />);
expect(screen.getByText(text)).toBeVisible();
if (role) {
expect(screen.getByRole(role)).toBeVisible();
}
});
});
const events: UpcomingRouteEvent[] = [
{
kind: "lock",
id: "lock-near",
name: "Schleuse Nah",
coordinate: { lat: 53.1, lon: 7.1 },
routeDistanceNm: 8,
distanceFromRouteNm: 0.02,
remainingNm: 3,
eta: eta("2026-07-23T12:30:00.000Z", 30),
feature: {
id: "lock-near",
name: "Schleuse Nah",
coordinate: { lat: 53.1, lon: 7.1 },
routeDistanceNm: 8,
distanceFromRouteNm: 0.02,
openingHours: "MoFr 08:0018:00",
phone: "+49 49 123456",
vhf: "Kanal 12",
website: "lock.example"
}
},
{
kind: "harbour",
id: "harbour-far",
name: "Hafen Weit",
coordinate: { lat: 53.3, lon: 7.3 },
routeDistanceNm: 17,
distanceFromRouteNm: 0.4,
remainingNm: 12,
eta: eta("2026-07-23T14:00:00.000Z", 120),
feature: {
id: "harbour-far",
name: "Hafen Weit",
coordinate: { lat: 53.3, lon: 7.3 },
kind: "marina",
amenities: { water: "available", electricity: true },
phone: null,
website: null
}
},
{
kind: "bridge",
id: "bridge-middle",
name: "Brücke Mitte",
coordinate: { lat: 53.2, lon: 7.2 },
routeDistanceNm: 11,
distanceFromRouteNm: 0.01,
remainingNm: 6,
eta: eta("2026-07-23T13:00:00.000Z", 60),
feature: {
id: "bridge-middle",
name: "Brücke Mitte",
label: "Brücke Mitte H 4,2 m",
coordinate: { lat: 53.2, lon: 7.2 },
distanceNm: 0.01,
clearanceM: 4.2,
clearanceLabel: "H 4,2 m",
requiredAirDraftM: 3.8,
marginM: 0.4,
status: "tight",
source: "Test",
phone: "+49 49 123457",
website: "bridge.example",
operator: "Brückenamt"
}
}
];
function eta(estimatedAt: string, minutesFromProgress: number) {
return {
estimatedAt,
minutesFromProgress,
speedKn: 6,
speedSource: "vessel-cruise-speed" as const,
referenceTime: "2026-07-23T12:00:00.000Z",
referenceSource: "current-time" as const
};
}