@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
JavaScript
;
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