From 68ca7df1774aa249c394abf6fb38738cfb4a4cc2 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 10 May 2026 03:53:32 +0200 Subject: [PATCH] test(routes): expand AppNav coverage for active links and mobile overlay Active-link styling per pathname (documents, persons, stammbaum, geschichten, admin), mobile backdrop click closes nav, Escape keypress on overlay closes nav. 7 new tests targeting ~14 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/routes/AppNav.svelte.test.ts | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/frontend/src/routes/AppNav.svelte.test.ts b/frontend/src/routes/AppNav.svelte.test.ts index 1d9c5cf5..6f89bffe 100644 --- a/frontend/src/routes/AppNav.svelte.test.ts +++ b/frontend/src/routes/AppNav.svelte.test.ts @@ -75,4 +75,83 @@ describe('AppNav', () => { .element(browserPage.getByRole('button', { name: /menü schließen/i })) .toHaveAttribute('aria-expanded', 'true'); }); + + it('marks the documents link as active when pathname starts with /documents', async () => { + mockPage.url = new URL('http://localhost/documents/abc'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: false } }); + + const link = Array.from(document.querySelectorAll('nav a[href="/documents"]'))[0]; + expect(link?.className).toContain('border-accent'); + }); + + it('marks the persons link as active when pathname starts with /persons', async () => { + mockPage.url = new URL('http://localhost/persons/123'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: false } }); + + const link = Array.from(document.querySelectorAll('nav a[href="/persons"]'))[0]; + expect(link?.className).toContain('border-accent'); + }); + + it('marks the stammbaum link as active when pathname starts with /stammbaum', async () => { + mockPage.url = new URL('http://localhost/stammbaum'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: false } }); + + const link = Array.from(document.querySelectorAll('nav a[href="/stammbaum"]'))[0]; + expect(link?.className).toContain('border-accent'); + }); + + it('marks the geschichten link as active when pathname starts with /geschichten', async () => { + mockPage.url = new URL('http://localhost/geschichten/x'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: false } }); + + const link = Array.from(document.querySelectorAll('nav a[href="/geschichten"]'))[0]; + expect(link?.className).toContain('border-accent'); + }); + + it('marks the admin link as active when pathname starts with /admin and isAdmin is true', async () => { + mockPage.url = new URL('http://localhost/admin/users'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: true } }); + + const link = Array.from(document.querySelectorAll('nav a[href="/admin"]'))[0]; + expect(link?.className).toContain('border-accent'); + }); + + it('closes the mobile nav when the backdrop is clicked', async () => { + mockPage.url = new URL('http://localhost/'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: false } }); + + await browserPage.getByRole('button', { name: /menü öffnen/i }).click(); + + // Mobile nav is now open + const backdrop = document.querySelector('.bg-black\\/20') as HTMLElement; + expect(backdrop).not.toBeNull(); + backdrop.click(); + + await new Promise((r) => setTimeout(r, 30)); + await expect + .element(browserPage.getByRole('button', { name: /menü öffnen/i })) + .toHaveAttribute('aria-expanded', 'false'); + }); + + it('closes the mobile nav when Escape is pressed on the overlay', async () => { + mockPage.url = new URL('http://localhost/'); + const AppNav = await loadComponent(); + render(AppNav, { props: { isAdmin: false } }); + + await browserPage.getByRole('button', { name: /menü öffnen/i }).click(); + + const overlay = document.querySelector('.fixed.inset-0') as HTMLElement; + overlay.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); + + await new Promise((r) => setTimeout(r, 30)); + await expect + .element(browserPage.getByRole('button', { name: /menü öffnen/i })) + .toHaveAttribute('aria-expanded', 'false'); + }); });