Agent skill
axe-accessibility
Deep integration with axe-core for automated accessibility testing. Execute accessibility scans, interpret WCAG violations, generate compliance reports, and integrate with Playwright/Cypress for comprehensive a11y testing.
Install this agent skill to your Project
npx add-skill https://github.com/a5c-ai/babysitter/tree/main/library/specializations/qa-testing-automation/skills/axe-accessibility
Metadata
Additional technical details for this skill
- author
- babysitter-sdk
- version
- 1.0.0
- category
- accessibility-testing
- backlog id
- SK-011
SKILL.md
axe-accessibility
You are axe-accessibility - a specialized skill for axe-core accessibility testing integration, providing comprehensive WCAG compliance validation capabilities.
Overview
This skill enables AI-powered accessibility testing including:
- Executing axe-core accessibility scans
- Interpreting WCAG violations and impacts
- Generating accessibility compliance reports
- Configuring rule inclusion/exclusion
- Integrating with Playwright/Cypress for automated a11y testing
- Handling dynamic content scanning
- Mapping violations to WCAG criteria
- Providing remediation guidance
Prerequisites
- Node.js environment for axe-core
- Test automation framework (Playwright, Cypress, or Selenium)
- Browser automation capability
- Optional: axe-playwright or axe-cypress packages
Capabilities
1. Playwright Integration
Use axe-core with Playwright for accessibility testing:
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test.describe('Accessibility Tests', () => {
test('homepage should have no violations', async ({ page }) => {
await page.goto('https://example.com');
const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
test('homepage should have no critical violations', 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('form page accessibility', async ({ page }) => {
await page.goto('https://example.com/contact');
// Wait for form to be fully loaded
await page.waitForSelector('form');
const results = await new AxeBuilder({ page })
.include('form')
.analyze();
// Log violations for debugging
if (results.violations.length > 0) {
console.log('Violations found:', JSON.stringify(results.violations, null, 2));
}
expect(results.violations).toEqual([]);
});
});
2. Cypress Integration
Use axe-core with Cypress:
// cypress/support/commands.js
import 'cypress-axe';
// cypress/e2e/accessibility.cy.js
describe('Accessibility Tests', () => {
beforeEach(() => {
cy.visit('/');
cy.injectAxe();
});
it('has no detectable accessibility violations on load', () => {
cy.checkA11y();
});
it('has no violations in main content', () => {
cy.checkA11y('#main-content');
});
it('has no critical violations', () => {
cy.checkA11y(null, {
includedImpacts: ['critical', 'serious']
});
});
it('logs violations for review', () => {
cy.checkA11y(null, null, (violations) => {
violations.forEach((violation) => {
cy.log(`${violation.id}: ${violation.description}`);
violation.nodes.forEach((node) => {
cy.log(` - ${node.target}`);
});
});
}, true);
});
});
3. Standalone axe-core Usage
Direct axe-core usage:
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);
// Inject axe-core
await page.addScriptTag({ path: require.resolve('axe-core') });
// Run analysis
const results = await page.evaluate(async () => {
return await axe.run();
});
await browser.close();
return results;
}
// Usage
const results = await runAccessibilityAudit('https://example.com');
console.log(`Found ${results.violations.length} violations`);
4. WCAG Compliance Configuration
Configure axe for specific WCAG standards:
import AxeBuilder from '@axe-core/playwright';
// WCAG 2.1 Level AA compliance
const wcag21AAResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
// WCAG 2.2 Level AA compliance
const wcag22AAResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
.analyze();
// Section 508 compliance
const section508Results = await new AxeBuilder({ page })
.withTags(['section508'])
.analyze();
// Best practices (not strict compliance)
const bestPracticesResults = await new AxeBuilder({ page })
.withTags(['best-practice'])
.analyze();
5. Rule Configuration
Include/exclude specific rules:
import AxeBuilder from '@axe-core/playwright';
const results = await new AxeBuilder({ page })
// Include only specific rules
.withRules(['color-contrast', 'image-alt', 'label', 'link-name'])
.analyze();
// Or exclude rules
const resultsExcluding = await new AxeBuilder({ page })
.disableRules(['region', 'landmark-one-main'])
.analyze();
// Focus on specific element
const formResults = await new AxeBuilder({ page })
.include('#contact-form')
.analyze();
// Exclude problematic areas
const mainResults = await new AxeBuilder({ page })
.exclude('#third-party-widget')
.analyze();
6. Violation Analysis
Analyze and categorize violations:
function analyzeViolations(results) {
const summary = {
total: results.violations.length,
byImpact: {},
byWCAG: {},
criticalIssues: []
};
for (const violation of results.violations) {
// Count by impact
summary.byImpact[violation.impact] =
(summary.byImpact[violation.impact] || 0) + violation.nodes.length;
// Count by WCAG criteria
for (const tag of violation.tags) {
if (tag.startsWith('wcag')) {
summary.byWCAG[tag] = (summary.byWCAG[tag] || 0) + 1;
}
}
// Collect critical issues
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. Report Generation
Generate accessibility reports:
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>Accessibility Report</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>Accessibility Report</h1>
<p>URL: ${report.url}</p>
<p>Generated: ${report.timestamp}</p>
<h2>Summary</h2>
<ul>
<li>Violations: ${report.summary.violations}</li>
<li>Passes: ${report.summary.passes}</li>
<li>Incomplete: ${report.summary.incomplete}</li>
</ul>
<h2>Violations (${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>How to fix:</strong> ${v.help}</p>
<p><a href="${v.helpUrl}" target="_blank">Learn more</a></p>
<p><strong>WCAG:</strong> ${v.wcagCriteria.join(', ')}</p>
<p><strong>Affected elements (${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 Integration
Integrate accessibility testing into pipelines:
# GitHub Actions
name: Accessibility Tests
on: [push, pull_request]
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run accessibility tests
run: npm run test:a11y
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: accessibility-report
path: accessibility-report.html
WCAG Criteria Reference
| Impact | Examples | Priority |
|---|---|---|
| Critical | Missing alt text, missing form labels | P1 - Fix immediately |
| Serious | Low color contrast, missing ARIA | P2 - Fix before release |
| Moderate | Skip link issues, heading order | P3 - Fix soon |
| Minor | Redundant ARIA, best practices | P4 - Backlog |
Common Violations
| Rule ID | Issue | Fix |
|---|---|---|
color-contrast |
Insufficient color contrast | Adjust foreground/background colors |
image-alt |
Missing image alt text | Add descriptive alt attribute |
label |
Form inputs without labels | Add associated label elements |
link-name |
Links without accessible names | Add link text or aria-label |
button-name |
Buttons without accessible names | Add button text or aria-label |
html-has-lang |
Missing lang attribute | Add lang to html element |
region |
Content not in landmark | Use semantic elements or ARIA |
MCP Server Integration
This skill can leverage the following MCP servers for enhanced capabilities:
| Server | Description | Installation |
|---|---|---|
| ronantakizawa/a11ymcp | Verified A11y MCP Server | GitHub |
| priyankark/a11y-mcp | axe-core MCP integration | GitHub |
| PashaBoiko/playwright-axe-mcp | Playwright Accessibility MCP | Glama |
| mcp-accessibility-scanner | Playwright + Axe-core scanner | Playbooks |
Best Practices
- Test early - Include a11y tests in development workflow
- Automate continuously - Run a11y tests in CI/CD
- Focus on impact - Prioritize critical and serious issues
- Manual verification - Complement automated tests with manual review
- Screen reader testing - Test with actual assistive technology
- Keyboard navigation - Verify full keyboard accessibility
- Document exceptions - Track and justify any rule exclusions
Process Integration
This skill integrates with the following processes:
accessibility-testing.js- All phases of a11y testinge2e-test-suite.js- A11y integration in E2E testsquality-gates.js- A11y compliance gatescontinuous-testing.js- CI/CD a11y integration
Output Format
When executing operations, provide structured output:
{
"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
}
}
Error Handling
- Handle page load failures gracefully
- Timeout handling for slow pages
- Retry logic for dynamic content
- Fallback for unsupported elements
- Clear error messages for configuration issues
Constraints
- Automated tests cannot catch all accessibility issues
- Manual testing with assistive technology is essential
- Some issues require human judgment
- Document false positive handling
- Consider user testing for complete validation
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
gsd-tools
Central utility skill for GSD operations. Provides config parsing, slug generation, timestamps, path operations, and orchestrates calls to other specialized skills. Acts as the unified entry point that the original gsd-tools.cjs provided via its lib/ modules (commands, config, core, init).
model-profile-resolution
Resolve model profile (quality/balanced/budget) at orchestration start and map agents to specific models. Enables cost/quality tradeoffs by selecting appropriate AI models for each agent role.
verification-suite
Plan structure validation, phase completeness checks, reference integrity verification, and artifact existence confirmation. Provides the structured verification layer ensuring GSD artifacts are well-formed and complete.
state-management
STATE.md reading, writing, and field-level updates. Provides cross-session state persistence via .planning/STATE.md with structured fields for current task, completed phases, blockers, decisions, and quick tasks.
git-integration
Git commit patterns, formats, and conventions for GSD methodology. Provides atomic commits per task, structured commit messages, planning file commits, branch management, and milestone tag operations.
frontmatter-parsing
YAML frontmatter parsing and manipulation for .planning/ documents. Provides read, write, update, query, and validation operations on frontmatter blocks in GSD markdown artifacts.
Didn't find tool you were looking for?