import { test, expect } from '@playwright/test'; test.describe('Accessibility', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); }); test('skip link is focusable and works', async ({ page }) => { // Tab to focus skip link await page.keyboard.press('Tab'); // Skip link should be visible when focused const skipLink = page.getByRole('link', { name: /skip to main content/i }); await expect(skipLink).toBeFocused(); await expect(skipLink).toBeVisible(); // Click skip link await skipLink.click(); // Focus should move to main content const main = page.locator('#main-content'); await expect(main).toBeFocused(); }); test('all interactive elements are keyboard accessible', async ({ page }) => { // Tab through the page and ensure focusable elements receive focus let focusedElements = 0; for (let i = 0; i < 20; i++) { await page.keyboard.press('Tab'); const focused = await page.evaluate(() => document.activeElement?.tagName); if (focused && ['A', 'BUTTON', 'INPUT'].includes(focused)) { focusedElements++; } } // Should have multiple focusable elements expect(focusedElements).toBeGreaterThan(5); }); test('pagination has correct aria attributes', async ({ page }) => { await page.goto('/blocks'); // Check pagination nav has correct role const pagination = page.getByRole('navigation', { name: /pagination/i }); await expect(pagination).toBeVisible(); // Current page should have aria-current const currentPage = page.locator('[aria-current="page"]'); await expect(currentPage).toBeVisible(); }); test('copy buttons have proper labels', async ({ page }) => { await page.goto('/blocks'); // Click first block to go to detail const firstBlock = page.locator('a[href^="/block/"]').first(); await firstBlock.click(); // Copy button should have accessible label const copyButton = page.getByRole('button', { name: /copy/i }).first(); await expect(copyButton).toBeVisible(); await expect(copyButton).toHaveAttribute('aria-label', /copy/i); }); test('connection status announces changes', async ({ page }) => { // Connection status should have aria-live const connectionStatus = page.locator('[aria-live="polite"]').filter({ hasText: /live|offline|connecting/i }); await expect(connectionStatus).toBeVisible(); await expect(connectionStatus).toHaveAttribute('aria-live', 'polite'); }); });