import { expect, test } from '@playwright/test'; test.describe('keyboard and palette', () => { test('skip link is first and moves focus to main', async ({ page }) => { await page.goto('/'); await page.keyboard.press('Tab'); const skip = page.locator('.skip-link'); await expect(skip).toBeFocused(); await page.keyboard.press('Enter'); await expect(page.locator('#main-content')).toBeFocused(); }); test('mobile nav toggle keeps aria-expanded in sync', async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); await page.goto('/'); const toggle = page.locator('.nav-toggle'); await expect(toggle).toBeVisible(); await expect(toggle).toHaveAttribute('aria-expanded', 'true'); await toggle.click(); await expect(toggle).toHaveAttribute('aria-expanded', 'false'); await toggle.click(); await expect(toggle).toHaveAttribute('aria-expanded', 'true'); }); test('palette opens with Control+K, traps focus, locks scroll and restores on Escape', async ({ page, }) => { await page.goto('/'); const trigger = page.locator('.command-palette-trigger'); await trigger.focus(); await page.keyboard.press('Control+k'); const dialog = page.locator('[role="dialog"]'); await expect(dialog).toBeVisible(); await expect(page.locator('.site')).toHaveAttribute('inert', ''); expect(await page.evaluate(() => document.body.style.overflow)).toBe('hidden'); const focusable = dialog.locator( 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled])', ); const count = await focusable.count(); const first = focusable.first(); const last = focusable.nth(count - 1); await last.focus(); await page.keyboard.press('Tab'); await expect(first).toBeFocused(); await page.keyboard.press('Shift+Tab'); await expect(last).toBeFocused(); await page.keyboard.press('Escape'); await expect(dialog).toHaveCount(0); await expect(page.locator('.site')).not.toHaveAttribute('inert'); expect(await page.evaluate(() => document.body.style.overflow)).toBe(''); await expect(trigger).toBeFocused(); }); });