From 091ff70deb3fc8c3ddd07d8d08715c18e5e31ae0 Mon Sep 17 00:00:00 2001 From: LucaP Date: Wed, 2 Sep 2026 03:12:12 +0300 Subject: [PATCH] test: lock semantic and no-script portfolio behavior --- playwright.config.ts | 4 + src/components/PortfolioSection.vue | 2 +- src/components/SiteNavigation.vue | 31 ++++- tests/browser/hydration.spec.ts | 133 ++++++++++++++++++ tests/browser/keyboard.spec.ts | 141 +++++++++++++++++++ tests/browser/no-javascript.spec.ts | 117 ++++++++++++++++ tests/browser/semantic.spec.ts | 179 ++++++++++++++++++++++++ tests/helpers/serve-dist.ts | 206 ++++++++++++++++++++++++++++ 8 files changed, 811 insertions(+), 2 deletions(-) create mode 100644 tests/browser/hydration.spec.ts create mode 100644 tests/browser/keyboard.spec.ts create mode 100644 tests/browser/no-javascript.spec.ts create mode 100644 tests/browser/semantic.spec.ts create mode 100644 tests/helpers/serve-dist.ts diff --git a/playwright.config.ts b/playwright.config.ts index 371154a..ff133fc 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,6 +2,10 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests/browser', + workers: 4, + use: { + serviceWorkers: 'block', + }, projects: [ { name: 'desktop-chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'mobile-chromium', use: { ...devices['Pixel 5'] } }, diff --git a/src/components/PortfolioSection.vue b/src/components/PortfolioSection.vue index 8ac7d5f..166cd2e 100644 --- a/src/components/PortfolioSection.vue +++ b/src/components/PortfolioSection.vue @@ -10,7 +10,7 @@ defineProps<{ diff --git a/src/components/SiteNavigation.vue b/src/components/SiteNavigation.vue index dbeb8fe..981d1a0 100644 --- a/src/components/SiteNavigation.vue +++ b/src/components/SiteNavigation.vue @@ -2,13 +2,42 @@ import type { SectionId } from '@/content/types'; defineProps<{ items: ReadonlyArray<{ id: SectionId; label: string }> }>(); + +const focusActivatedSection = (event: MouseEvent): void => { + if ( + event.defaultPrevented || + event.button !== 0 || + event.altKey || + event.ctrlKey || + event.metaKey || + event.shiftKey || + !(event.currentTarget instanceof HTMLAnchorElement) + ) { + return; + } + + let sectionId: string; + try { + sectionId = decodeURIComponent(event.currentTarget.hash.slice(1)); + } catch { + return; + } + + const section = document.getElementById(sectionId); + const heading = section?.querySelector( + ':scope > h2[tabindex="-1"]', + ); + if (heading === undefined || heading === null) return; + + requestAnimationFrame(() => heading.focus({ preventScroll: true })); +};