Files
jiapu/tests/form-labels.test.js
T
2026-08-03 16:49:38 +08:00

38 lines
1.6 KiB
JavaScript

const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const projectRoot = path.join(__dirname, '..');
test('all visible form controls have a label or accessible name', () => {
const pages = fs.readdirSync(projectRoot).filter((name) => name.endsWith('.html'));
pages.forEach((page) => {
const source = fs.readFileSync(path.join(projectRoot, page), 'utf8');
Array.from(source.matchAll(/<form\b[\s\S]*?<\/form>/gi)).forEach((form) => {
const formHtml = form[0];
Array.from(formHtml.matchAll(/<(input|select|textarea)\b[^>]*>/gi)).forEach((control) => {
const tag = control[0];
const type = (tag.match(/\btype=["']([^"']+)/i) || [, ''])[1].toLowerCase();
const id = (tag.match(/\bid=["']([^"']+)/i) || [, ''])[1];
const name = (tag.match(/\bname=["']([^"']+)/i) || [, ''])[1] || 'unnamed control';
const before = formHtml.slice(0, control.index);
const hasExplicitLabel = Boolean(id) && (
formHtml.includes('for="' + id + '"') || formHtml.includes("for='" + id + "'")
);
const hasImplicitLabel = before.lastIndexOf('<label') > before.lastIndexOf('</label');
const hasAccessibleName = /\baria-label(?:ledby)?=["'][^"']+/i.test(tag);
if (['hidden', 'submit', 'button', 'reset'].includes(type) || /\bhidden\b/i.test(tag)) return;
assert.ok(
hasExplicitLabel || hasImplicitLabel || hasAccessibleName,
page + ' control ' + name + ' has no label or accessible name'
);
});
});
});
});