@casoon/auditmysite
Version:
A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs
105 lines • 5.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SemanticHtmlTest = void 0;
const base_test_1 = require("../base-test");
class SemanticHtmlTest extends base_test_1.BaseAccessibilityTest {
constructor() {
super(...arguments);
this.name = 'Semantic HTML';
this.description = 'Check for proper semantic HTML structure';
this.category = 'semantic';
this.priority = 'medium';
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 heading hierarchy
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
const headingLevels = [];
headings.forEach((heading) => {
const level = parseInt(heading.tagName.charAt(1));
headingLevels.push(level);
});
// Check for proper heading hierarchy
for (let i = 1; i < headingLevels.length; i++) {
if (headingLevels[i] - headingLevels[i - 1] > 1) {
totalIssues++;
issues.push(`Heading hierarchy skipped: h${headingLevels[i - 1]} followed by h${headingLevels[i]}`);
}
}
// Check for multiple h1 elements
const h1Elements = document.querySelectorAll('h1');
if (h1Elements.length > 1) {
warnings.push(`Multiple h1 elements found (${h1Elements.length})`);
}
// Check for semantic elements
const semanticElements = document.querySelectorAll('main, nav, header, footer, section, article, aside');
const divElements = document.querySelectorAll('div');
const semanticRatio = semanticElements.length / (semanticElements.length + divElements.length);
if (semanticRatio < 0.1) {
warnings.push(`Low semantic HTML usage: ${(semanticRatio * 100).toFixed(1)}% semantic elements`);
}
// Check for lists
const lists = document.querySelectorAll('ul, ol');
const listItems = document.querySelectorAll('li');
const orphanedListItems = document.querySelectorAll('li:not(ul li):not(ol li)');
if (orphanedListItems.length > 0) {
totalIssues++;
issues.push(`${orphanedListItems.length} list items outside of list containers`);
}
// Check for tables
const tables = document.querySelectorAll('table');
tables.forEach((table) => {
const tableElement = table;
const hasCaption = tableElement.querySelector('caption');
const hasThead = tableElement.querySelector('thead');
const hasTbody = tableElement.querySelector('tbody');
if (!hasCaption) {
warnings.push(`Table missing caption: ${tableElement.outerHTML}`);
}
if (!hasThead && !hasTbody) {
warnings.push(`Table missing thead or tbody: ${tableElement.outerHTML}`);
}
});
// Check for proper list structure
const definitionLists = document.querySelectorAll('dl');
definitionLists.forEach((dl) => {
const hasDt = dl.querySelector('dt');
const hasDd = dl.querySelector('dd');
if (!hasDt || !hasDd) {
totalIssues++;
issues.push(`Definition list missing dt or dd: ${dl.outerHTML}`);
}
});
return {
totalIssues,
issues,
warnings,
stats: {
headings: headings.length,
semanticElements: semanticElements.length,
divElements: divElements.length,
semanticRatio,
lists: lists.length,
listItems: listItems.length,
tables: tables.length
}
};
});
return this.createResult(result.totalIssues === 0, result.totalIssues, result.issues, result.warnings, {
category: 'semantic-html',
stats: result.stats
});
}
catch (error) {
return this.createErrorResult(`Semantic HTML test failed: ${error}`);
}
}
}
exports.SemanticHtmlTest = SemanticHtmlTest;
//# sourceMappingURL=semantic-html-test.js.map