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

122 lines 4.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccessibilityChecker = void 0; const playwright_1 = require("playwright"); const pa11y_1 = __importDefault(require("pa11y")); class AccessibilityChecker { constructor() { this.browser = null; } async initialize() { this.browser = await playwright_1.chromium.launch({ headless: true }); } async cleanup() { if (this.browser) { await this.browser.close(); } } async testPage(url, options = {}) { if (!this.browser) { throw new Error("Browser not initialized"); } const startTime = Date.now(); const page = await this.browser.newPage(); const result = { url, title: "", imagesWithoutAlt: 0, buttonsWithoutLabel: 0, headingsCount: 0, errors: [], warnings: [], passed: true, duration: 0, }; try { await page.goto(url, { waitUntil: options.waitUntil || "domcontentloaded", timeout: options.timeout || 10000, }); // Seitentitel prüfen result.title = await page.title(); // Bilder ohne alt-Attribut result.imagesWithoutAlt = await page.locator("img:not([alt])").count(); if (result.imagesWithoutAlt > 0) { result.warnings.push(`${result.imagesWithoutAlt} images without alt attribute`); } // Buttons ohne aria-label result.buttonsWithoutLabel = await page .locator("button:not([aria-label])") .filter({ hasText: "" }) .count(); if (result.buttonsWithoutLabel > 0) { result.warnings.push(`${result.buttonsWithoutLabel} buttons without aria-label`); } // Überschriften-Hierarchie result.headingsCount = await page .locator("h1, h2, h3, h4, h5, h6") .count(); if (result.headingsCount === 0) { result.errors.push("No headings found"); } // pa11y Accessibility-Tests durchführen try { const pa11yResult = await (0, pa11y_1.default)(url, { timeout: options.timeout || 10000, wait: 1000, // Warten nach dem Laden standard: 'WCAG2AA', // WCAG 2.0 Level AA hideElements: 'iframe[src*="google-analytics"], iframe[src*="doubleclick"]', // Tracking-Iframes ausblenden includeNotices: true, includeWarnings: true, }); // pa11y-Ergebnisse in unser Format konvertieren pa11yResult.issues.forEach((issue) => { const message = `${issue.code}: ${issue.message}`; if (issue.type === 'error') { result.errors.push(message); } else if (issue.type === 'warning') { result.warnings.push(message); } else if (issue.type === 'notice') { result.warnings.push(`Notice: ${message}`); } }); // Zusätzliche pa11y-Metriken if (pa11yResult.documentTitle) { result.title = pa11yResult.documentTitle; } } catch (pa11yError) { result.warnings.push(`pa11y test failed: ${pa11yError}`); } // Prüfe auf kritische Fehler if (result.errors.length > 0) { result.passed = false; } } catch (error) { result.errors.push(`Navigation error: ${error}`); result.passed = false; } finally { await page.close(); result.duration = Date.now() - startTime; } return result; } async testMultiplePages(urls, options = {}) { const results = []; const maxPages = options.maxPages || urls.length; for (let i = 0; i < Math.min(urls.length, maxPages); i++) { const result = await this.testPage(urls[i], options); results.push(result); } return results; } } exports.AccessibilityChecker = AccessibilityChecker; //# sourceMappingURL=accessibility-checker.js.map