import { test, expect } from '@playwright/test'; test.describe('无障碍测试 @feature @frontend', () => { test('首页无障碍检查', async ({ page }) => { await page.goto('/'); const violations = await page.evaluate(() => { return (window as unknown as { axe?: { run: () => unknown[] } }).axe?.run() || []; }); expect(violations.length).toBe(0); }); test('导航键盘可访问', async ({ page }) => { await page.goto('/'); await page.keyboard.press('Tab'); const focusedElement = page.locator(':focus'); await expect(focusedElement).toBeVisible(); }); test('图片有alt属性', async ({ page }) => { await page.goto('/'); const images = page.locator('img'); const count = await images.count(); for (let i = 0; i < count; i++) { const img = images.nth(i); const alt = await img.getAttribute('alt'); expect(alt).not.toBeNull(); } }); test('表单标签关联正确', async ({ page }) => { await page.goto('/contact'); const inputs = page.locator('input[type="text"], input[type="email"], textarea'); const count = await inputs.count(); for (let i = 0; i < count; i++) { const input = inputs.nth(i); const id = await input.getAttribute('id'); if (id) { const label = page.locator(`label[for="${id}"]`); const hasLabel = await label.count() > 0; const hasAriaLabel = await input.getAttribute('aria-label'); expect(hasLabel || hasAriaLabel).toBeTruthy(); } } }); test('标题层级正确', async ({ page }) => { await page.goto('/'); const h1 = page.locator('h1'); const h1Count = await h1.count(); expect(h1Count).toBeGreaterThanOrEqual(1); expect(h1Count).toBeLessThanOrEqual(1); }); test('链接有明确的文本', async ({ page }) => { await page.goto('/'); await page.waitForLoadState('domcontentloaded'); const links = page.locator('a'); const count = await links.count(); const problematicLinks: string[] = []; for (let i = 0; i < Math.min(count, 20); i++) { const link = links.nth(i); const text = await link.textContent(); const ariaLabel = await link.getAttribute('aria-label'); const title = await link.getAttribute('title'); const href = await link.getAttribute('href'); const hasAccessibleName = text?.trim() || ariaLabel || title; const isSpecialLink = !href || href === '#' || href.startsWith('javascript:') || href.startsWith('mailto:'); if (!hasAccessibleName && !isSpecialLink) { const linkHtml = await link.innerHTML(); problematicLinks.push(`链接 ${i + 1}: href="${href}", innerHTML="${linkHtml}"`); console.log(`链接 ${i + 1} 缺少可访问名称: href="${href}", innerHTML="${linkHtml}"`); } } if (problematicLinks.length > 0) { console.log('\n缺少可访问名称的链接列表:'); problematicLinks.forEach(link => console.log(link)); } expect(problematicLinks.length).toBe(0); }); });