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); }); test("zoom control buttons update mapZoom", async ({ page }) => { 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"); // Wait for Leaflet map and custom zoom controls await page.locator("#map.leaflet-container").waitFor({ state: "visible", timeout: 20_000 }); const zoomInBtn = page.getByTestId("zoom-in"); const zoomOutBtn = page.getByTestId("zoom-out"); await expect(zoomInBtn).toBeVisible(); await expect(zoomOutBtn).toBeVisible(); const z0 = await getZoomFromLocalStorage(page); await zoomInBtn.click(); await waitForZoomChange(page, z0, "gt"); const z1 = await getZoomFromLocalStorage(page); expect(z1).toBeGreaterThan(z0); await zoomOutBtn.click(); await waitForZoomChange(page, z1, "lt"); const z2 = await getZoomFromLocalStorage(page); expect(z2).toBeLessThan(z1); });