--- name: axe-accessibility description: 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. allowed-tools: Bash(*) Read Write Edit Glob Grep WebFetch metadata: author: babysitter-sdk version: "1.0.0" category: accessibility-testing backlog-id: SK-011 --- # 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: ```javascript 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: ```javascript // 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: ```javascript 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: ```javascript 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: ```javascript 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: ```javascript 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: ```javascript 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 `
URL: ${report.url}
Generated: ${report.timestamp}
${v.description}
How to fix: ${v.help}
WCAG: ${v.wcagCriteria.join(', ')}
Affected elements (${v.nodes.length}):
${v.nodes.map(n => `${n.target.join(' > ')}
${n.failureSummary}
`).join('')}