axe-accessibility
你是 axe-accessibility - 一个专门用于axe-core无障碍测试集成的特殊技能,提供全面的WCAG合规性验证能力。
概览
这个技能使得AI驱动的无障碍测试成为可能,包括:
- 执行axe-core无障碍扫描
- 解释WCAG违规和影响
- 生成无障碍合规性报告
- 配置规则包含/排除
- 与Playwright/Cypress集成进行自动化a11y测试
- 处理动态内容扫描
- 将违规行为映射到WCAG标准
- 提供补救指导
前提条件
- Node.js环境用于axe-core
- 测试自动化框架(Playwright,Cypress或Selenium)
- 浏览器自动化能力
- 可选:axe-playwright或axe-cypress包
能力
1. Playwright集成
使用axe-core与Playwright进行无障碍测试:
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test.describe('无障碍测试', () => {
test('首页不应有违规行为', async ({ page }) => {
await page.goto('https://example.com');
const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
test('首页不应有严重违规行为', async ({ page }) => {
await page.goto('https://example.com');
const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.analyze();
const criticalViolations = accessibilityScanResults.violations
.filter(v => v.impact === 'critical' || v.impact === 'serious');
expect(criticalViolations).toEqual([]);
});
test('表单页面无障碍性', async ({ page }) => {
await page.goto('https://example.com/contact');
// 等待表单完全加载
await page.waitForSelector('form');
const results = await new AxeBuilder({ page })
.include('form')
.analyze();
// 日志违规行为以供调试
if (results.violations.length > 0) {
console.log('发现违规行为:', JSON.stringify(results.violations, null, 2));
}
expect(results.violations).toEqual([]);
});
});
2. Cypress集成
使用axe-core与Cypress:
// cypress/support/commands.js
import 'cypress-axe';
// cypress/e2e/accessibility.cy.js
describe('无障碍测试', () => {
beforeEach(() => {
cy.visit('/');
cy.injectAxe();
});
it('加载时没有可检测到的无障碍违规行为', () => {
cy.checkA11y();
});
it('主要内容中没有违规行为', () => {
cy.checkA11y('#main-content');
});
it('没有严重违规行为', () => {
cy.checkA11y(null, {
includedImpacts: ['critical', 'serious']
});
});
it('记录违规行为以供审查', () => {
cy.checkA11y(null, null, (violations) => {
violations.forEach((violation) => {
cy.log(`${violation.id}: ${violation.description}`);
violation.nodes.forEach((node) => {
cy.log(` - ${node.target}`);
});
});
}, true);
});
});
3. 独立的axe-core使用
直接axe-core使用:
import { chromium } from 'playwright';
import axe from 'axe-core';
async function runAccessibilityAudit(url) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
// 注入axe-core
await page.addScriptTag({ path: require.resolve('axe-core') });
// 运行分析
const results = await page.evaluate(async () => {
return await axe.run();
});
await browser.close();
return results;
}
// 使用
const results = await runAccessibilityAudit('https://example.com');
console.log`发现 ${results.violations.length} 违规行为');
4. WCAG合规性配置
为特定WCAG标准配置axe:
import AxeBuilder from '@axe-core/playwright';
// WCAG 2.1 Level AA合规性
const wcag21AAResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
// WCAG 2.2 Level AA合规性
const wcag22AAResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
.analyze();
// Section 508合规性
const section508Results = await new AxeBuilder({ page })
.withTags(['section508'])
.analyze();
// 最佳实践(不严格合规)
const bestPracticesResults = await new AxeBuilder({ page })
.withTags(['best-practice'])
.analyze();
5. 规则配置
包含/排除特定规则:
import AxeBuilder from '@axe-core/playwright';
const results = await new AxeBuilder({ page })
// 只包含特定规则
.withRules(['color-contrast', 'image-alt', 'label', 'link-name'])
.analyze();
// 或排除规则
const resultsExcluding = await new AxeBuilder({ page })
.disableRules(['region', 'landmark-one-main'])
.analyze();
// 专注于特定元素
const formResults = await new AxeBuilder({ page })
.include('#contact-form')
.analyze();
// 排除有问题的区域
const mainResults = await new AxeBuilder({ page })
.exclude('#third-party-widget')
.analyze();
6. 违规行为分析
分析和分类违规行为:
function analyzeViolations(results) {
const summary = {
total: results.violations.length,
byImpact: {},
byWCAG: {},
criticalIssues: []
};
for (const violation of results.violations) {
// 按影响计数
summary.byImpact[violation.impact] =
(summary.byImpact[violation.impact] || 0) + violation.nodes.length;
// 按WCAG标准计数
for (const tag of violation.tags) {
if (tag.startsWith('wcag')) {
summary.byWCAG[tag] = (summary.byWCAG[tag] || 0) + 1;
}
}
// 收集严重问题
if (violation.impact === 'critical' || violation.impact === 'serious') {
summary.criticalIssues.push({
id: violation.id,
impact: violation.impact,
description: violation.description,
help: violation.help,
helpUrl: violation.helpUrl,
affectedElements: violation.nodes.length
});
}
}
return summary;
}
7. 报告生成
生成无障碍报告:
function generateA11yReport(results, format = 'html') {
const report = {
timestamp: new Date().toISOString(),
url: results.url,
summary: {
violations: results.violations.length,
passes: results.passes.length,
incomplete: results.incomplete.length,
inapplicable: results.inapplicable.length
},
violations: results.violations.map(v => ({
id: v.id,
impact: v.impact,
description: v.description,
help: v.help,
helpUrl: v.helpUrl,
wcagCriteria: v.tags.filter(t => t.startsWith('wcag')),
nodes: v.nodes.map(n => ({
target: n.target,
html: n.html,
failureSummary: n.failureSummary
}))
}))
};
if (format === 'html') {
return generateHtmlReport(report);
}
return JSON.stringify(report, null, 2);
}
function generateHtmlReport(report) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>无障碍报告</title>
<style>
body { font-family: -apple-system, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }
.violation { border: 1px solid #ddd; margin: 10px 0; padding: 15px; border-radius: 4px; }
.critical { border-left: 4px solid #d32f2f; }
.serious { border-left: 4px solid #f57c00; }
.moderate { border-left: 4px solid #fbc02d; }
.minor { border-left: 4px solid #388e3c; }
.impact { padding: 2px 8px; border-radius: 4px; font-size: 12px; }
h1 { color: #333; }
pre { background: #f5f5f5; padding: 10px; overflow-x: auto; }
</style>
</head>
<body>
<h1>无障碍报告</h1>
<p>URL: ${report.url}</p>
<p>生成: ${report.timestamp}</p>
<h2>摘要</h2>
<ul>
<li>违规行为: ${report.summary.violations}</li>
<li>通过: ${report.summary.passes}</li>
<li>不完整: ${report.summary.incomplete}</li>
</ul>
<h2>违规行为 (${report.violations.length})</h2>
${report.violations.map(v => `
<div class="violation ${v.impact}">
<h3>${v.id} <span class="impact">${v.impact}</span></h3>
<p>${v.description}</p>
<p><strong>如何修复:</strong> ${v.help}</p>
<p><a href="${v.helpUrl}" target="_blank">了解更多</a></p>
<p><strong>WCAG:</strong> ${v.wcagCriteria.join(', ')}</p>
<p><strong>受影响元素 (${v.nodes.length}):</strong></p>
${v.nodes.map(n => `
<pre>${n.target.join(' > ')}</pre>
<p>${n.failureSummary}</p>
`).join('')}
</div>
`).join('')}
</body>
</html>
`;
}
8. CI/CD集成
将无障碍测试集成到流程中:
# GitHub Actions
name: 无障碍测试
on: [push, pull_request]
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 设置Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 安装依赖
run: npm ci
- name: 安装Playwright浏览器
run: npx playwright install --with-deps
- name: 运行无障碍测试
run: npm run test:a11y
- name: 上传报告
if: always()
uses: actions/upload-artifact@v4
with:
name: accessibility-report
path: accessibility-report.html
WCAG标准参考
| 影响 | 示例 | 优先级 |
|---|---|---|
| 严重 | 缺少alt文本,缺少表单标签 | P1 - 立即修复 |
| 严重 | 低对比度颜色,缺少ARIA | P2 - 发布前修复 |
| 中等 | 跳过链接问题,标题顺序 | P3 - 尽快修复 |
| 轻微 | 多余的ARIA,最佳实践 | P4 - 待办事项 |
常见违规行为
| 规则ID | 问题 | 修复 |
|---|---|---|
color-contrast |
颜色对比度不足 | 调整前景/背景颜色 |
image-alt |
缺少图像alt文本 | 添加描述性alt属性 |
label |
表单输入缺少标签 | 添加相关联的标签元素 |
link-name |
链接没有可访问名称 | 添加链接文本或aria-label |
button-name |
按钮没有可访问名称 | 添加按钮文本或aria-label |
html-has-lang |
缺少lang属性 | 在html元素上添加lang |
region |
内容不在地标中 | 使用语义元素或ARIA |
MCP服务器集成
这个技能可以利用以下MCP服务器增强能力:
| 服务器 | 描述 | 安装 |
|---|---|---|
| ronantakizawa/a11ymcp | 经过验证的A11y MCP服务器 | GitHub |
| priyankark/a11y-mcp | axe-core MCP集成 | GitHub |
| PashaBoiko/playwright-axe-mcp | Playwright无障碍MCP | Glama |
| mcp-accessibility-scanner | Playwright + Axe-core扫描器 | Playbooks |
最佳实践
- 早期测试 - 在开发工作流程中包含a11y测试
- 持续自动化 - 在CI/CD中运行a11y测试
- 关注影响 - 优先处理严重和严重问题
- 手动验证 - 用手动审查补充自动化测试
- 屏幕阅读器测试 - 用实际辅助技术进行测试
- 键盘导航 - 验证完整的键盘可访问性
- 记录例外 - 跟踪并证明任何规则排除
流程集成
这个技能与以下流程集成:
accessibility-testing.js- a11y测试的所有阶段e2e-test-suite.js- E2E测试中a11y集成quality-gates.js- a11y合规性门continuous-testing.js- CI/CD a11y集成
输出格式
执行操作时,提供结构化输出:
{
"operation": "scan",
"url": "https://example.com",
"wcagLevel": "AA",
"status": "completed",
"summary": {
"violations": 5,
"passes": 42,
"incomplete": 2,
"inapplicable": 15
},
"criticalIssues": [
{
"id": "color-contrast",
"impact": "serious",
"count": 3,
"wcag": "wcag143"
}
],
"reportPath": "./accessibility-report.html",
"compliance": {
"wcag2a": true,
"wcag2aa": false,
"section508": true
}
}
错误处理
- 优雅地处理页面加载失败
- 慢速页面的超时处理
- 动态内容的重试逻辑
- 不支持元素的回退
- 配置问题清晰的错误信息
限制
- 自动化测试不能捕获所有无障碍问题
- 使用辅助技术进行手动测试是必要的
- 一些问题需要人类判断
- 文档处理误报
- 考虑用户测试以获得完整验证