Nota 07 / Accessibilità
Playwright e axe: un controllo che può fallire
Verifica l’accessibilità sulla pagina renderizzata. Scansiona desktop e mobile e dimostra che il controllo rilevi un errore.
Il sorgente non è la pagina renderizzata
Un template può sembrare semanticamente corretto e mostrare nel browser testo poco contrastato o un pulsante senza nome. Cascata CSS, menu e banner cookie cambiano il risultato. Per questo devi verificare la pagina servita, con fogli di stile e font effettivamente caricati.
Il controllo seguente visita lo stesso URL in due viste, esegue axe e termina con errore se trova serious o critical. Controlla anche se il contenuto supera la larghezza del viewport. Le larghezze sono condizioni di prova, non un’affermazione sui dispositivi dei visitatori.
Un controllo minimo eseguibile
Salva il codice in axe-check.mjs. Installa playwright e axe-core, poi Chromium con npx playwright install chromium. Esegui node axe-check.mjs http://127.0.0.1:8769/engineering/. L’URL deve servire una vera pagina HTML; anche gli errori HTTP interrompono il controllo.
import { chromium } from 'playwright';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const browser = await chromium.launch();
let failed = false;
try {
for (const width of [1440, 390]) {
const page = await browser.newPage({ viewport: { width, height: 900 } });
const response = await page.goto(process.argv[2], { waitUntil: 'load' });
if (!response?.ok()) throw new Error(`HTTP ${response?.status()}`);
await page.evaluate(() => document.fonts.ready);
await page.addScriptTag({ path: require.resolve('axe-core/axe.min.js') });
const results = await page.evaluate(() => axe.run(document));
const blocking = results.violations.filter(
issue => ['serious', 'critical'].includes(issue.impact)
);
const overflow = await page.evaluate(
() => document.documentElement.scrollWidth > innerWidth
);
console.log(JSON.stringify({ width, blocking, overflow,
incomplete: results.incomplete }));
failed ||= blocking.length > 0 || overflow;
await page.close();
}
} finally {
await browser.close();
}
process.exitCode = failed ? 1 : 0;
Attiva intenzionalmente il percorso di errore
Il test locale serve una piccola fixture accessibile e poi la stessa fixture con un pulsante senza nome accessibile. Il primo comando deve riuscire; il secondo deve fallire e segnalare button-name. Così verifichi che il processo non si limiti a stampare axe mantenendo l’esito verde. Un’altra fixture restituisce un errore HTTP.
Per Engineering il verificatore estende il controllo alle tre lingue, al banner aperto e chiuso, ai link, alla SEO e al contrasto del codice. Le verifiche e le alterazioni intenzionali avvengono solo in locale. Non modificano alcuna pagina pubblica.
Le verifiche automatiche hanno limiti
Zero rilievi serious o critical non significa conformità WCAG completa. Esamina i casi incomplete e verifica tastiera, ordine del focus, zoom, chiarezza dei link e qualità dei testi alternativi. axe non valuta se una spiegazione tecnica sia comprensibile o una traduzione naturale.
Il controllo minimo non apre menu e non chiude banner. Gli stati interattivi richiedono passaggi aggiuntivi e nuove scansioni. Fissa le versioni degli strumenti nel lockfile e conserva i rilievi insieme agli screenshot: da sola un’immagine non dimostra contrasto o usabilità.