Accessibility Testing
axe-core, Lighthouse, screen reader testing, and automated a11y checks.
Overview
Automated testing helps catch accessibility issues early in development.
Key Concepts
- axe-core — Accessibility testing engine
- jest-axe — Jest integration for axe
- Lighthouse — Performance and accessibility audits
- Screen Reader Testing — Manual testing with NVDA, VoiceOver
- Color Contrast — Ensure sufficient contrast ratios
Code Examples
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
describe('Button accessibility', () => {
it('should have no accessibility violations', async () => {
const { container } = render(<Button>Click me</Button>);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should have proper ARIA attributes', () => {
render(
<button aria-label="Close dialog" aria-pressed={false}>
×
</button>
);
const button = screen.getByRole('button', { name: /close dialog/i });
expect(button).toHaveAttribute('aria-pressed', 'false');
});
});
// Custom hook for a11y testing
function useA11yAudit() {
useEffect(() => {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
checkNewElements(mutation.addedNodes);
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
return () => observer.disconnect();
}, []);
}
function checkNewElements(nodes) {
nodes.forEach((node) => {
if (node.nodeType === 1) {
// Check for missing alt text on images
if (node.tagName === 'IMG' && !node.hasAttribute('alt')) {
console.warn('Image missing alt text:', node);
}
// Check for empty links
if (node.tagName === 'A' && !node.textContent.trim()) {
console.warn('Empty link:', node);
}
}
});
}
Practice
Write accessibility tests for a form component and fix any violations found.