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

112 lines 6.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidationErrorHandlingTest = void 0; const base_test_1 = require("../base-test"); class ValidationErrorHandlingTest extends base_test_1.BaseAccessibilityTest { constructor() { super(...arguments); this.name = 'Validation Error Handling Test'; this.description = 'Checks error handling, accessibility, and user experience (error messages, screen readers, error recovery)'; this.category = 'validation'; this.priority = 'high'; 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 = []; // Check for error messages and their accessibility const errorMessages = document.querySelectorAll('.error, .error-message, .alert-error, [role="alert"], [aria-invalid="true"]'); if (errorMessages.length === 0) { // Check for other common error patterns const errorPatterns = document.querySelectorAll('[class*="error"], [class*="invalid"], [class*="alert"]'); if (errorPatterns.length === 0) { warnings.push('No error handling patterns detected (consider adding error states)'); } } else { // Check if error messages are properly associated with form controls errorMessages.forEach(error => { const formControl = error.closest('form')?.querySelector('input, select, textarea'); if (formControl && !formControl.hasAttribute('aria-describedby')) { issues.push('Error message not properly associated with form control (missing aria-describedby)'); } }); } // Check for required field indicators in error handling context const requiredFields = document.querySelectorAll('input[required], select[required], textarea[required]'); requiredFields.forEach(field => { const label = document.querySelector(`label[for="${field.id}"]`); if (label && !label.textContent?.includes('*') && !label.textContent?.includes('required')) { warnings.push(`Required field "${field.id}" not clearly indicated in label text`); } }); // Check for validation feedback patterns in error handling context const formInputs = document.querySelectorAll('input, select, textarea'); let hasValidation = false; formInputs.forEach(input => { if (input.hasAttribute('pattern') || input.hasAttribute('minlength') || input.hasAttribute('maxlength')) { hasValidation = true; } }); if (!hasValidation && formInputs.length > 0) { warnings.push('No client-side validation patterns detected for error handling'); } // Check for error recovery mechanisms const forms = document.querySelectorAll('form'); forms.forEach(form => { const resetButton = form.querySelector('button[type="reset"], input[type="reset"]'); if (!resetButton) { warnings.push('Form lacks reset/clear functionality for error recovery'); } }); // Check for error message visibility const hiddenErrors = document.querySelectorAll('.error[style*="display: none"], .error[hidden], .error[aria-hidden="true"]'); if (hiddenErrors.length > 0) { issues.push('Error messages are hidden from screen readers'); } // Check for error message clarity const errorTexts = Array.from(errorMessages).map(el => el.textContent?.trim()).filter(Boolean); errorTexts.forEach(text => { if (text && text.length < 10) { warnings.push('Error message may be too brief: "' + text + '"'); } }); // Check for error message positioning errorMessages.forEach(error => { const rect = error.getBoundingClientRect(); if (rect.top < 0 || rect.left < 0) { warnings.push('Error message positioned outside viewport'); } }); // Check for error message color contrast (basic check) const computedStyle = window.getComputedStyle(errorMessages[0] || document.body); const color = computedStyle.color; const backgroundColor = computedStyle.backgroundColor; if (color && backgroundColor && (color.includes('red') || backgroundColor.includes('red'))) { // This is a basic check - in a real implementation, you'd use a color contrast library warnings.push('Error messages should ensure sufficient color contrast'); } // Check for error message timing const autoHideErrors = document.querySelectorAll('.error[data-auto-hide], .error[data-timeout]'); if (autoHideErrors.length > 0) { warnings.push('Auto-hiding error messages may not be accessible to all users'); } // Check for error message persistence const persistentErrors = document.querySelectorAll('.error[data-persistent="true"]'); if (persistentErrors.length === 0 && errorMessages.length > 0) { warnings.push('Consider making error messages persistent until user action'); } return { issues, warnings }; }); return this.createResult(result.issues.length === 0, result.issues.length + result.warnings.length, result.issues, result.warnings); } catch (error) { return this.createErrorResult(`Validation error handling test failed: ${error}`); } } } exports.ValidationErrorHandlingTest = ValidationErrorHandlingTest; //# sourceMappingURL=validation-error-handling-test.js.map