@casoon/auditmysite
Version:
A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs
90 lines • 4.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.KeyboardNavigationTest = void 0;
const base_test_1 = require("../base-test");
class KeyboardNavigationTest extends base_test_1.BaseAccessibilityTest {
constructor() {
super(...arguments);
this.name = 'Keyboard Navigation';
this.description = 'Check if all interactive elements are keyboard accessible';
this.category = 'keyboard';
this.priority = 'critical';
this.standards = ['WCAG 2.1 AA', 'WCAG 2.2 AA', 'Section 508'];
}
async run(context) {
const { page } = context;
try {
const result = await this.evaluateOnPage(page, () => {
const issues = [];
const warnings = [];
let totalIssues = 0;
// Check focusable elements
const focusableSelectors = [
'button:not([disabled])',
'input:not([disabled]):not([type="hidden"])',
'select:not([disabled])',
'textarea:not([disabled])',
'a[href]',
'[tabindex]:not([tabindex="-1"])',
'[role="button"]:not([disabled])',
'[role="link"]',
'[role="menuitem"]',
'[role="tab"]',
'[role="option"]'
];
const focusableElements = document.querySelectorAll(focusableSelectors.join(', '));
// Check for elements that should be focusable but aren't
const interactiveElements = document.querySelectorAll('button, input, select, textarea, a');
interactiveElements.forEach((element) => {
const interactiveElement = element;
const isDisabled = interactiveElement.hasAttribute('disabled');
const isHidden = interactiveElement.style.display === 'none' ||
interactiveElement.style.visibility === 'hidden' ||
interactiveElement.hidden;
if (!isDisabled && !isHidden) {
const tabIndex = interactiveElement.tabIndex;
if (tabIndex === -1) {
totalIssues++;
issues.push(`Interactive element with tabindex="-1": ${interactiveElement.outerHTML}`);
}
}
});
// Check for skip links
const skipLinks = document.querySelectorAll('a[href^="#"]');
if (skipLinks.length === 0) {
warnings.push('No skip links found for keyboard navigation');
}
// Check for focus indicators
const focusableWithoutIndicator = Array.from(focusableElements).filter((element) => {
const el = element;
const style = window.getComputedStyle(el);
return style.outline === 'none' &&
style.border === 'none' &&
!el.classList.contains('focus') &&
!el.classList.contains('focus-visible');
});
if (focusableWithoutIndicator.length > 0) {
totalIssues++;
warnings.push(`${focusableWithoutIndicator.length} focusable elements without visible focus indicators`);
}
return {
totalIssues,
issues,
warnings,
focusableCount: focusableElements.length,
skipLinksCount: skipLinks.length
};
});
return this.createResult(result.totalIssues === 0, result.totalIssues, result.issues, result.warnings, {
category: 'keyboard-navigation',
focusableCount: result.focusableCount,
skipLinksCount: result.skipLinksCount
});
}
catch (error) {
return this.createErrorResult(`Keyboard navigation test failed: ${error}`);
}
}
}
exports.KeyboardNavigationTest = KeyboardNavigationTest;
//# sourceMappingURL=keyboard-navigation-test.js.map