UNPKG

@progress/kendo-e2e

Version:

Kendo UI end-to-end test utilities.

122 lines 5.13 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateIdReferences = validateIdReferences; exports.formatIdRefValidation = formatIdRefValidation; exports.formatIdRefForLLM = formatIdRefForLLM; const sanitize_html_1 = __importDefault(require("sanitize-html")); const parse_html_1 = require("./parse-html"); /** Attributes whose values are space-separated lists of ID references */ const ID_REF_ATTRIBUTES = ['aria-controls', 'aria-labelledby', 'aria-owns', 'aria-describedby']; // ============= Validation ============= /** * Validate that ID-referencing aria attributes in the actual HTML point to * elements that actually exist in the same DOM. * * Checks `aria-controls`, `aria-labelledby`, `aria-owns`, and `aria-describedby`. * Each attribute value is treated as a space-separated list of ID tokens * (per the WAI-ARIA spec). * * @param actualHtml The actual HTML markup to validate. * @returns An `IdRefResult` with `valid` and `invalid` reference lists. */ function validateIdReferences(actualHtml) { const result = { valid: [], invalid: [] }; const config = { allowedTags: false, allowVulnerableTags: true, allowedAttributes: { "*": ["class", "id", "role", "aria-*"] }, }; const doc = (0, parse_html_1.parseHtml)((0, sanitize_html_1.default)(actualHtml, config)); // Collect all IDs in the DOM const allIds = new Set(); for (const el of doc.querySelectorAll('[id]')) { const id = el.getAttribute('id'); if (id) allIds.add(id); } // Walk all elements that have ID-referencing attributes for (const attrName of ID_REF_ATTRIBUTES) { for (const el of doc.querySelectorAll(`[${attrName}]`)) { const value = el.getAttribute(attrName); if (!value) continue; const selector = buildClassSelector(el); const ids = value.split(/\s+/).filter(Boolean); for (const id of ids) { if (allIds.has(id)) { result.valid.push({ selector, attribute: attrName, id }); } else { result.invalid.push({ selector, attribute: attrName, missingId: id }); } } } } return result; } /** Build a CSS class selector string from an element (e.g. ".k-button.k-button-md") */ function buildClassSelector(el) { const classAttr = el.getAttribute('class') || ''; const classes = classAttr.split(/\s+/).filter(Boolean).sort(); return classes.length > 0 ? '.' + classes.join('.') : el.tagName.toLowerCase(); } // ============= Formatting ============= const helpers_1 = require("./helpers"); /** * Format ID reference validation results for terminal output. */ function formatIdRefValidation(result, options) { const c = (options === null || options === void 0 ? void 0 : options.useColors) ? helpers_1.ANSI : helpers_1.NO_ANSI; const sep = '═'.repeat(62); const thinSep = '─'.repeat(62); const lines = []; lines.push(''); lines.push(`${c.dim}${sep}${c.reset}`); lines.push(`${c.bold} A11Y ID REFERENCE VALIDATION${c.reset}`); lines.push(`${c.dim}${sep}${c.reset}`); lines.push(''); lines.push(` ${c.green}${result.valid.length} valid${c.reset}` + (result.invalid.length > 0 ? ` ${c.red}${result.invalid.length} broken${c.reset}` : '')); if (result.invalid.length === 0) { lines.push(''); lines.push(` ${c.green}All ID references resolve to existing elements!${c.reset}`); lines.push(`${c.dim}${sep}${c.reset}`); return lines.join('\n'); } lines.push(''); lines.push(`${c.dim}${thinSep}${c.reset}`); lines.push(`${c.bold}${c.red} BROKEN ID REFERENCES${c.reset}${c.red} (attribute points to non-existent ID):${c.reset}`); lines.push(`${c.dim}${thinSep}${c.reset}`); for (const issue of result.invalid) { lines.push(` ${c.red}${issue.selector} ${issue.attribute}="${issue.missingId}" → ID not found${c.reset}`); } lines.push(''); lines.push(`${c.dim}${sep}${c.reset}`); return lines.join('\n'); } /** * Format ID reference validation as LLM-friendly plain text. */ function formatIdRefForLLM(result) { const thin = '-'.repeat(60); const lines = []; lines.push(''); lines.push(thin); lines.push('ID REFERENCE VALIDATION'); lines.push(thin); lines.push(`IDREF_STATUS: ${result.invalid.length === 0 ? 'PASS' : 'FAIL'}`); lines.push(`IDREF_VALID: ${result.valid.length}`); lines.push(`IDREF_BROKEN: ${result.invalid.length}`); if (result.invalid.length > 0) { lines.push(''); lines.push('BROKEN_IDREFS:'); for (const issue of result.invalid) { lines.push(` ✗ ${issue.selector} ${issue.attribute}="${issue.missingId}" → ID not found`); } } return lines.join('\n'); } //# sourceMappingURL=a11y-id-validator.js.map