UNPKG

@casoon/auditmysite

Version:

A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs

108 lines 6.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FormLabelTest = void 0; const base_test_1 = require("../base-test"); class FormLabelTest extends base_test_1.BaseAccessibilityTest { constructor() { super(...arguments); this.name = 'Form Label Association'; this.description = 'Check form controls for proper label associations and accessibility (labels, aria-label, aria-labelledby, aria-describedby)'; this.category = 'form'; 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 inputs without labels (focus on label associations only) const inputs = document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="image"])'); inputs.forEach((input) => { const inputElement = input; const hasLabel = inputElement.labels && inputElement.labels.length > 0; const hasAriaLabel = inputElement.hasAttribute('aria-label'); const hasAriaLabelledBy = inputElement.hasAttribute('aria-labelledby'); const hasPlaceholder = inputElement.hasAttribute('placeholder'); if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy && !hasPlaceholder) { totalIssues++; issues.push(`Input without label: ${inputElement.outerHTML}`); } }); // Check labels without for attribute or nested controls const labels = document.querySelectorAll('label'); labels.forEach((label) => { const labelElement = label; if (!labelElement.hasAttribute('for') && !labelElement.querySelector('input, select, textarea')) { totalIssues++; warnings.push(`Label without for attribute or nested control: ${labelElement.outerHTML}`); } }); // Check selects without labels const selects = document.querySelectorAll('select'); selects.forEach((select) => { const selectElement = select; const hasLabel = selectElement.labels && selectElement.labels.length > 0; const hasAriaLabel = selectElement.hasAttribute('aria-label'); const hasAriaLabelledBy = selectElement.hasAttribute('aria-labelledby'); if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy) { totalIssues++; issues.push(`Select without label: ${selectElement.outerHTML}`); } }); // Check textareas without labels const textareas = document.querySelectorAll('textarea'); textareas.forEach((textarea) => { const textareaElement = textarea; const hasLabel = textareaElement.labels && textareaElement.labels.length > 0; const hasAriaLabel = textareaElement.hasAttribute('aria-label'); const hasAriaLabelledBy = textareaElement.hasAttribute('aria-labelledby'); const hasPlaceholder = textareaElement.hasAttribute('placeholder'); if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy && !hasPlaceholder) { totalIssues++; issues.push(`Textarea without label: ${textareaElement.outerHTML}`); } }); // Check for proper label associations (accessibility focus) const formControls = document.querySelectorAll('input, select, textarea'); formControls.forEach(control => { const controlElement = control; // Check if control has proper ID for label association if (controlElement.id) { const associatedLabel = document.querySelector(`label[for="${controlElement.id}"]`); if (associatedLabel) { // Check if label text is descriptive const labelText = associatedLabel.textContent?.trim(); if (!labelText || labelText.length < 2) { warnings.push(`Label for "${controlElement.id}" has insufficient text: "${labelText}"`); } } } // Check for aria-describedby associations if (controlElement.hasAttribute('aria-describedby')) { const describedBy = controlElement.getAttribute('aria-describedby'); if (describedBy) { const describedElement = document.getElementById(describedBy); if (!describedElement) { issues.push(`aria-describedby references non-existent element: ${describedBy}`); } } } }); return { totalIssues, issues, warnings }; }); return this.createResult(result.totalIssues === 0, result.totalIssues, result.issues, result.warnings, { category: 'form-labels' }); } catch (error) { return this.createErrorResult(`Form label test failed: ${error}`); } } } exports.FormLabelTest = FormLabelTest; //# sourceMappingURL=form-label-test.js.map