From 01b902e885ba140b780bfd09699d80b18e1e26ab Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 29 May 2026 19:06:06 +0200 Subject: [PATCH] test(stammbaum): assert zoom-out floor via mirrored ?z; e2e affordance beforeEach (#692) Strengthen the zoom-clamp test to assert z floors at 0.25 in the URL (was a 'does not throw' smoke test) and move the affordance localStorage reset to a beforeEach so the e2e tests are order-independent (QA review). Co-Authored-By: Claude Opus 4.8 --- frontend/e2e/stammbaum-mobile.visual.spec.ts | 7 ++++++- frontend/src/routes/stammbaum/page.svelte.test.ts | 13 +++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/frontend/e2e/stammbaum-mobile.visual.spec.ts b/frontend/e2e/stammbaum-mobile.visual.spec.ts index 6de8c48b..4cb7b196 100644 --- a/frontend/e2e/stammbaum-mobile.visual.spec.ts +++ b/frontend/e2e/stammbaum-mobile.visual.spec.ts @@ -17,10 +17,15 @@ test.describe('Stammbaum — mobile read path (#692)', () => { // affordance appears; reduced-motion is already forced project-wide. test.use({ hasTouch: true, isMobile: true }); + // Clear the affordance-dismissed flag before every test so the first-load + // hint state is deterministic regardless of test order. + test.beforeEach(async ({ page }) => { + await page.addInitScript(() => localStorage.removeItem('stammbaumAffordanceDismissedAt')); + }); + for (const width of WIDTHS) { test(`affordance + controls render at ${width}px`, async ({ page }) => { await page.setViewportSize({ width, height: 720 }); - await page.addInitScript(() => localStorage.removeItem('stammbaumAffordanceDismissedAt')); await page.goto('/stammbaum'); await expect(page.getByRole('heading', { name: 'Stammbaum' })).toBeVisible(); diff --git a/frontend/src/routes/stammbaum/page.svelte.test.ts b/frontend/src/routes/stammbaum/page.svelte.test.ts index bdeacd5b..839f66c9 100644 --- a/frontend/src/routes/stammbaum/page.svelte.test.ts +++ b/frontend/src/routes/stammbaum/page.svelte.test.ts @@ -88,17 +88,22 @@ describe('stammbaum page', () => { await expect.element(page.getByRole('complementary')).not.toBeInTheDocument(); }); - it('clamps the zoom level when the zoom-out button is clicked many times', async () => { + it('clamps zoom-out at MIN_ZOOM (0.25), reflected in the mirrored ?z param', async () => { mockPage.url = new URL('http://localhost/stammbaum'); + replaceState.mockClear(); const Stammbaum = await loadComponent(); render(Stammbaum, { props: { data: { nodes: sampleNodes, edges: [], initialView: DEFAULT_VIEW } } }); const zoomOut = page.getByRole('button', { name: /verkleinern/i }); - for (let i = 0; i < 10; i++) await zoomOut.click(); - // Just verify that repeated clicks don't throw — branch coverage - await expect.element(zoomOut).toBeVisible(); + // Default z=1; well over (1 - 0.25) / 0.1 = 8 steps to reach the floor. + for (let i = 0; i < 15; i++) await zoomOut.click(); + + await vi.waitFor(() => { + const url = replaceState.mock.calls.at(-1)![0] as URL; + expect(url.searchParams.get('z')).toBe('0.25'); + }); }); it('mirrors the view into ?cx&cy&z when zoomed (US-PANEL-002 AC2)', async () => {