Files
nodeMap/playwright/tests/mapcomponent.spec.js
2025-09-16 11:47:04 +02:00

271 lines
9.8 KiB
JavaScript

import { test, expect } from "@playwright/test";
/**
* Helper: Pan the Leaflet map by simulating a mouse drag and wait until
* mapCenter in localStorage changes (MapComponent persists center on move/zoom).
*
* Note for codegen: The recorder oft erfasst Klicks statt Drag. Ersetze
* die aufgenommenen Klicks nachträglich durch diesen Helper für verlässliches Panning.
*/
async function panMap(page, deltaY = -200) {
const map = page.locator("#map");
await map.waitFor({ state: "visible" });
// Wait until Leaflet initializes the container class
await page.locator("#map.leaflet-container").waitFor({ state: "visible", timeout: 20_000 });
const centerBefore = await page.evaluate(() => {
try {
const v = localStorage.getItem("mapCenter");
return v ? JSON.parse(v) : null;
} catch {
return null;
}
});
const box = await map.boundingBox();
if (!box) throw new Error("Map bounding box not found");
const startX = box.x + box.width / 2;
const startY = box.y + box.height / 2;
await page.mouse.move(startX, startY);
await page.mouse.down();
await page.mouse.move(startX, startY + deltaY, { steps: 12 });
await page.mouse.up();
await page.waitForFunction(
prev => {
try {
const v = localStorage.getItem("mapCenter");
if (!v) return false;
if (!prev) return true; // previously null -> now set
const c = JSON.parse(v);
const dLat = Math.abs(c[0] - prev[0]);
const dLng = Math.abs(c[1] - prev[1]);
return dLat > 0.0005 || dLng > 0.0005;
} catch {
return false;
}
},
centerBefore,
{ timeout: 15_000 }
);
}
/**
* Helper: Move mouse to the visual center of the #map element.
*/
async function moveMouseToMapCenter(page) {
const map = page.locator("#map");
await map.waitFor({ state: "visible" });
await page.locator("#map.leaflet-container").waitFor({ state: "visible", timeout: 20_000 });
const box = await map.boundingBox();
if (!box) throw new Error("Map bounding box not found");
const cx = box.x + box.width / 2;
const cy = box.y + box.height / 2;
await page.mouse.move(cx, cy);
return { cx, cy };
}
/**
* Helper: Read map zoom from localStorage as a number. Returns NaN if not set.
*/
async function getZoomFromLocalStorage(page) {
return await page.evaluate(() => {
const v = localStorage.getItem("mapZoom");
return v ? Number(v) : NaN;
});
}
/**
* Helper: Wait until mapZoom in localStorage changes compared to a previous value.
* Optionally enforce a direction via compareFn(newZoom, oldZoom) => boolean.
*/
async function waitForZoomChange(page, previousZoom, compareFn) {
await page.waitForFunction(
(prev, cmp) => {
const v = localStorage.getItem("mapZoom");
if (!v) return false;
const z = Number(v);
if (Number.isNaN(z)) return false;
if (typeof cmp === "string" && cmp === "gt") return z > prev;
if (typeof cmp === "string" && cmp === "lt") return z < prev;
if (typeof cmp === "string" && cmp === "ne") return z !== prev;
return z !== prev;
},
previousZoom,
{ timeout: 10_000 }
);
}
/**
* Helper: Zoom the map using wheel input at map center.
* Uses page.mouse.wheel when available; otherwise dispatches a WheelEvent in the page context.
* Negative deltaY zooms in; positive deltaY zooms out.
*/
async function wheelZoom(page, deltaY = -400) {
const { cx, cy } = await moveMouseToMapCenter(page);
// Try native Playwright wheel first
try {
await page.mouse.wheel(0, deltaY);
return;
} catch {
// Fallback: dispatch a real WheelEvent at the map element
await page.evaluate(
({ selector, deltaY, cx, cy }) => {
const el = document.querySelector(selector);
if (!el) return false;
const evt = new WheelEvent("wheel", {
deltaY,
clientX: cx,
clientY: cy,
bubbles: true,
cancelable: true,
view: window,
});
el.dispatchEvent(evt);
return true;
},
{ selector: "#map", deltaY, cx, cy }
);
}
}
// Attach localStorage snapshot on failure to aid debugging
test.afterEach(async ({ page }, testInfo) => {
// Only capture on unexpected failure
if (testInfo.status !== testInfo.expectedStatus) {
const snapshot = await page.evaluate(() => {
const keys = [
"mapZoom",
"mapCenter",
"showAppInfoCard",
"showCoordinateInput",
"showLayersPanel",
"showAreaDropdown",
"currentMapId",
"currentUserId",
];
const out = {};
for (const k of keys) out[k] = localStorage.getItem(k);
return out;
});
// Attach as artifact and also log for convenience
await testInfo.attach("localStorage.json", {
contentType: "application/json",
body: JSON.stringify(snapshot, null, 2),
});
// eslint-disable-next-line no-console
console.log("[localStorage snapshot]", snapshot);
}
});
test("MapComponent", async ({ page }) => {
await page.goto("http://localhost:3000/?m=12&u=484");
// 10 Sekunden warten, bis die Karte sichtbar ist
await page.locator("#map").waitFor({ state: "visible", timeout: 10_000 });
// Set your keys before the page loads (from your screenshot)
await page.addInitScript(() => {
localStorage.setItem("editMode", "false");
localStorage.setItem("polylineVisible_m12_u484", "true");
localStorage.setItem("currentMapId", "12");
localStorage.setItem("currentUserId", "484");
localStorage.setItem("mapZoom", "13");
localStorage.setItem("kabelstreckenVisible", "false"); // legacy, not used for init
localStorage.setItem("showBaseMapPanel", "false");
localStorage.setItem("mapLayersVisibility_m12_u484", {
"system-1": true,
"system-2": false,
"system-3": false,
"system-5": false,
"system-6": false,
"system-7": false,
"system-8": false,
"system-9": false,
"system-10": false,
"system-11": false,
"system-13": false,
"system-30": false,
"system-100": false,
"system-110": false,
"system-111": false,
"system-200": false,
});
localStorage.setItem("mapCenter", [53.23938294961826, 8.21434020996094]);
localStorage.setItem("markerLink", "undefined");
localStorage.setItem("lastElementType", "marker");
localStorage.setItem("polylineVisible", "false"); // global legacy
localStorage.setItem("showAppInfoCard", "false");
localStorage.setItem("showCoordinateInput", "false");
localStorage.setItem("showLayersPanel", "false");
});
// test steps
await expect(
page.locator("div").filter({ hasText: "TALASKabelstreckenULAFGSM" }).nth(3)
).toBeVisible();
await page.getByRole("button", { name: "Layer-Panel ausblenden" }).click();
await page.getByRole("button", { name: "Layer-Panel einblenden" }).click();
await expect(
page.locator("div").filter({ hasText: "TALASKabelstreckenULAFGSM" }).nth(3)
).toBeVisible();
await page.getByRole("button", { name: "Layer-Panel ausblenden" }).click();
await expect(page.getByRole("button", { name: "Info ausblenden" })).toBeVisible();
await page.getByRole("button", { name: "Info ausblenden" }).click();
await page.getByRole("button", { name: "Info einblenden" }).click();
await expect(page.locator("div").filter({ hasText: "TALAS.Map Version" }).nth(3)).toBeVisible();
await page.getByRole("button", { name: "Info ausblenden" }).click();
// Warten, bis der Button-Text wechselt, bevor erneut geklickt wird
await expect(page.getByRole("button", { name: "Info einblenden" })).toBeVisible({
timeout: 10000,
});
await page.getByRole("button", { name: "Info einblenden" }).click();
await expect(page.locator("div").filter({ hasText: "TALAS.Map Version" }).nth(3)).toBeVisible();
await page.getByRole("button", { name: "Koordinatensuche einblenden" }).click();
await expect(page.locator("form")).toBeVisible();
await page.getByRole("button", { name: "Koordinatensuche ausblenden" }).click();
await page.getByRole("button", { name: "Info ausblenden" }).click();
await page.getByLabel("Marker").click();
await expect(page.getByText("Station wählenBitte wählen…")).toBeVisible();
await page.getByRole("combobox").selectOption("50977");
await page.getByLabel("Marker").click();
await page.getByRole("combobox").selectOption("50986");
await page.getByLabel("Marker").click();
await page.getByLabel("Marker").click();
await page.getByLabel("Marker").click();
await page.getByRole("combobox").selectOption("50977");
await page.getByRole("button", { name: "Karte auf Standardansicht" }).click();
});
test("mouse wheel zoom updates mapZoom", async ({ page }) => {
// Set initial state before navigation so the app can read them on load
await page.addInitScript(() => {
localStorage.setItem("currentMapId", "12");
localStorage.setItem("currentUserId", "484");
localStorage.setItem("mapCenter", JSON.stringify([53.23938294961826, 8.21434020996094]));
localStorage.setItem("mapZoom", "10");
localStorage.setItem("showAppInfoCard", "false");
localStorage.setItem("showCoordinateInput", "false");
localStorage.setItem("showLayersPanel", "false");
localStorage.setItem("showAreaDropdown", "false");
});
await page.goto("http://localhost:3000/?m=12&u=484");
await page.locator("#map.leaflet-container").waitFor({ state: "visible", timeout: 20_000 });
const before = await getZoomFromLocalStorage(page);
expect(Number.isNaN(before)).toBeFalsy();
// Zoom in via wheel and expect zoom to increase
await wheelZoom(page, -600);
await waitForZoomChange(page, before, "gt");
const afterIn = await getZoomFromLocalStorage(page);
expect(afterIn).toBeGreaterThan(before);
// Zoom out via wheel and expect zoom to decrease
await wheelZoom(page, 800);
await waitForZoomChange(page, afterIn, "lt");
const afterOut = await getZoomFromLocalStorage(page);
expect(afterOut).toBeLessThan(afterIn);
});