import { expect, expectInsetFocusIndicator, test } from "../helpers/serve-dist"; const navHrefs = [ "#start", "#profile", "#experience", "#infrastructure", "#selected-builds", "#additional-work", "#toolkit", "#contact", ] as const; const assertVisibleUnobscuredFocus = async ( page: import("@playwright/test").Page, ): Promise => { await expect .poll(() => page.evaluate(() => { const active = document.activeElement; if (!(active instanceof HTMLElement)) return false; const rect = active.getBoundingClientRect(); const left = Math.max(0, rect.left); const right = Math.min(window.innerWidth, rect.right); const top = Math.max(0, rect.top); const bottom = Math.min(window.innerHeight, rect.bottom); if (right <= left || bottom <= top) return false; const x = left + (right - left) / 2; const y = top + (bottom - top) / 2; const topElement = document.elementFromPoint(x, y); const style = getComputedStyle(active); return ( topElement !== null && (active === topElement || active.contains(topElement) || topElement.contains(active)) && style.outlineStyle !== "none" && Number.parseFloat(style.outlineWidth) >= 2 ); }), ) .toBe(true); }; test("tabs from the skip link through navigation and every contact action", async ({ page, distUrl, }, testInfo) => { test.skip( testInfo.project.name === "mobile-chromium", "The compact disclosure path is covered by the adaptive keyboard traversal suite.", ); await page.goto(distUrl, { waitUntil: "domcontentloaded" }); const expectedTargets = [ { selector: ".skip-link", href: "#portfolio-content" }, ...navHrefs.map((href) => ({ selector: `nav a[href="${href}"]`, href })), { selector: '.hero-journey__action--primary', href: 'mailto:luca.pislaru@gmail.com' }, { selector: '.hero-journey__actions a[href="#selected-builds"]', href: "#selected-builds" }, { selector: 'a[href="https://github.com/LucaPisl/footy-tracker"]', href: "https://github.com/LucaPisl/footy-tracker", }, { selector: 'a[href="https://github.com/LucaPisl/opinion-dynamics-simulation"]', href: "https://github.com/LucaPisl/opinion-dynamics-simulation", }, { selector: 'a[href="https://github.com/LucaPisl/CurrencyConverterAvalonia"]', href: "https://github.com/LucaPisl/CurrencyConverterAvalonia", }, { selector: 'a[href="https://github.com/LucaPisl/LinuxModdingGuide"]', href: "https://github.com/LucaPisl/LinuxModdingGuide", }, { selector: '#contact a[href^="mailto:"]', href: "mailto:luca.pislaru@gmail.com", }, { selector: '#contact a[href="https://github.com/LucaPisl"]', href: "https://github.com/LucaPisl", }, { selector: '#contact a[href="https://gitlab.com/luca_pisl"]', href: "https://gitlab.com/luca_pisl", }, { selector: '#contact a[href="https://linkedin.com/in/luca-pisl"]', href: "https://linkedin.com/in/luca-pisl", }, ]; for (const target of expectedTargets) { await page.keyboard.press("Tab"); const locator = page.locator(target.selector); await expect(locator).toBeFocused(); await expect(locator).toHaveAttribute("href", target.href); await assertVisibleUnobscuredFocus(page); } }); test("activating the skip link focuses the visible unobscured portfolio content", async ({ page, distUrl, }) => { await page.goto(distUrl, { waitUntil: "domcontentloaded" }); await page.keyboard.press("Tab"); await expect(page.locator(".skip-link")).toBeFocused(); await page.keyboard.press("Enter"); await expect(page).toHaveURL(`${distUrl}/#portfolio-content`); await expect(page.locator("#portfolio-content")).toBeFocused(); await expect(page.locator("#portfolio-content")).toHaveAttribute( "tabindex", "-1", ); await expectInsetFocusIndicator(page, "#portfolio-content"); }); test("explicit section activation scrolls to and focuses its heading", async ({ page, distUrl, }, testInfo) => { test.skip( testInfo.project.name === "mobile-chromium", "The full keyboard path already covers the mobile project.", ); await page.goto(distUrl, { waitUntil: "domcontentloaded" }); for (let index = 0; index < 5; index += 1) await page.keyboard.press("Tab"); await expect(page.locator('nav a[href="#infrastructure"]')).toBeFocused(); await page.keyboard.press("Enter"); await expect(page).toHaveURL(`${distUrl}/#infrastructure`); await expect(page.locator("#infrastructure")).toBeInViewport(); await expect(page.locator("#infrastructure-heading")).toHaveAttribute( "tabindex", "-1", ); await expect(page.locator("#infrastructure-heading")).toBeFocused(); await assertVisibleUnobscuredFocus(page); }); test("manual wheel and PageDown scrolling never move focus", async ({ page, distUrl, }, testInfo) => { test.skip( testInfo.project.name === "mobile-chromium", "The focus invariant is engine-level rather than viewport-specific.", ); await page.goto(distUrl, { waitUntil: "domcontentloaded" }); await page.keyboard.press("Tab"); await page.keyboard.press("Tab"); const startLink = page.locator('nav a[href="#start"]'); await expect(startLink).toBeFocused(); await page.mouse.wheel(0, 900); await expect(startLink).toBeFocused(); await page.keyboard.press("PageDown"); await expect(startLink).toBeFocused(); }); test("direct fragments do not steal focus while reduced-motion navigation remains accessible", async ({ page, distUrl, }, testInfo) => { test.skip( testInfo.project.name === "mobile-chromium", "The full keyboard path already covers the mobile project.", ); await page.emulateMedia({ reducedMotion: "reduce" }); await page.goto(`${distUrl}/#toolkit`, { waitUntil: "domcontentloaded" }); await expect(page.locator("#toolkit-heading")).not.toBeFocused(); await page.locator('nav a[href="#contact"]').click(); await expect(page).toHaveURL(`${distUrl}/#contact`); await expect(page.locator("#contact-heading")).toBeFocused(); await expect(page.locator("#contact")).toBeInViewport(); });