Pular para o conteúdo
Análise de Dados

Testes automatizados e auditoria manual para garantir acessibilidade web

Admin5 min de leitura
Testes automatizados e auditoria manual para garantir acessibilidade web

Testes automatizados e auditoria manual para garantir acessibilidade web

“A acessibilidade não é um recurso opcional; é a base de uma experiência digital verdadeiramente inclusiva.”

A construção de interfaces que atendam a todas as pessoas vai muito além de aplicar algumas regras de estilo. É preciso adotar uma cultura de desenvolvimento que combine testes automatizados, auditoria manual e boas práticas de código. Neste artigo, vamos explorar passo a passo como integrar essas práticas ao seu fluxo de trabalho, garantindo conformidade com as diretrizes WCAG 2.2 e proporcionando uma experiência fluida para usuários de leitores de tela, navegação por teclado e outras tecnologias assistivas.

Tecnologia e Inovação

1. Por que combinar testes automatizados e auditoria manual?

AspectoTestes AutomatizadosAuditoria Manual
VelocidadeExecuta milhares de verificações em segundosDemanda tempo, mas foca em nuances
CoberturaDetecta problemas de markup, contraste, atributos ARIA faltantesAvalia fluxo de navegação, linguagem, contexto
ConsistênciaRepete o mesmo conjunto de regras em todas as buildsAdapta-se a mudanças de design e conteúdo
FeedbackIntegração direta em CI/CD, bloqueia mergesRelatórios qualitativos, recomendações de usabilidade

A combinação permite que você identifique rapidamente falhas técnicas (por exemplo, falta de alt em imagens) e, ao mesmo tempo, avalie a experiência real do usuário, como a ordem de foco ou a clareza de mensagens de erro.


2. Configurando o ambiente de testes automatizados

2.1 Ferramentas recomendadas

  • axe-core (npm) – biblioteca JavaScript que roda no navegador ou em Node.
  • Pa11y – CLI que gera relatórios de conformidade.
  • Lighthouse – auditoria integrada ao Chrome DevTools, inclui métricas de acessibilidade.
  • Storybook Accessibility Addon – valida componentes UI isolados.

2.2 Exemplo: Integração do axe-core com Jest

Instale as dependências:

npm install --save-dev jest axe-core @axe-core/webdriverjs selenium-webdriver

Crie o teste accessibility.test.js:

// accessibility.test.js

const {Builder, By} = require('selenium-webdriver'); const axe = require('axe-core');

describe('Acessibilidade da página principal', () => { let driver;

beforeAll(async () => { driver = await new Builder().forBrowser('chrome').build(); await driver.get('http://localhost:3000'); });

afterAll(async () => { await driver.quit(); });

test('não deve ter violações de acessibilidade', async () => { const source = await driver.getPageSource(); const results = await driver.executeAsyncScript((cb) => { axe.run((err, result) => { if (err) cb(err); else cb(result); }); });

// Falha se houver qualquer violação expect(results.violations).toHaveLength(0); }); });

Dica: Execute esse teste em seu pipeline de CI/CD. Se o número de violações for maior que zero, o build falha, garantindo que nenhum código novo quebre a acessibilidade.

2.3 Testando contraste de cores com Pa11y

npm install -g pa11y

pa11y http://localhost:3000 --reporter json > relatorio-acessibilidade.json

O JSON gerado contém linhas como:

{

"code": "WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail", "type": "error", "message": "Insufficient color contrast (foreground: #777777, background: #FFFFFF).", "context": "<p style=\"color:#777777;\">..." }

Use esses dados para corrigir contrastes críticos antes do próximo deploy.


3. Boas práticas de markup e ARIA

3.1 Estrutura semântica

  • Use
    ,
  • Evite
    puro para componentes interativos; prefira

3.2 ARIA landmarks

<body>

<header role="banner"> <h1>Minha Aplicação</h1> </header>

<nav role="navigation" aria-label="Menu principal"> <ul> <li><a href="/dashboard">Dashboard</a></li> <li><a href="/relatorios">Relatórios</a></li> </ul> </nav>

<main role="main"> <!-- Conteúdo principal --> </main>

<footer role="contentinfo"> © 2026 Minha Empresa </footer> </body>

Os landmarks permitem que leitores de tela pulem rapidamente para áreas importantes.

3.3 Controle de foco

Um dos erros mais comuns é perder o foco ao abrir modais ou menus. O código abaixo cria um focus trap simples em JavaScript:

<!-- Modal -->

<div id="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title" hidden> <h2 id="modal-title">Confirmar ação</h2> <p>Deseja realmente excluir este item?</p> <button id="confirmBtn">Confirmar</button> <button id="cancelBtn">Cancelar</button> </div>

<button id="openModal">Abrir modal</button>

// focus-trap.js

const modal = document.getElementById('modal'); const openBtn = document.getElementById('openModal'); const focusableEls = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'; let firstFocusable, lastFocusable;

function openModal() { modal.hidden = false; const focusables = modal.querySelectorAll(focusableEls); firstFocusable = focusables[0]; lastFocusable = focusables[focusables.length - 1]; firstFocusable.focus(); }

function closeModal() { modal.hidden = true; openBtn.focus(); }

openBtn.addEventListener('click', openModal); modal.addEventListener('keydown', (e) => { if (e.key !== 'Tab') return;

if (e.shiftKey) { // Shift + Tab if (document.activeElement === firstFocusable) { e.preventDefault(); lastFocusable.focus(); } } else { // Tab if (document.activeElement === lastFocusable) { e.preventDefault(); firstFocusable.focus(); } } });

document.getElementById('cancelBtn').addEventListener('click', closeModal); document.getElementById('confirmBtn').addEventListener('click', () => { // ação de confirmação closeModal(); });

Esse script garante que, enquanto o modal estiver aberto, o foco circule apenas dentro dele, evitando que usuários de teclado fiquem presos no conteúdo de fundo.


4. Auditoria manual: checklist essencial

Mesmo com ferramentas, a visita humana continua indispensável. Use a checklist abaixo em cada release:

ItemComo validarFerramentas auxiliares
Leitura de telaNavegue usando NVDA (Windows) ou VoiceOver (macOS). Verifique se as informações são anunciadas na ordem correta.NVDA, VoiceOver
Navegação por tecladoUse Tab, Shift+Tab, Enter e Esc. Certifique‑se de que todos os controles são acessíveis e que não há focus traps inesperados.Chrome DevTools (Focus outline)
ContrasteVerifique manualmente com a extensão WCAG Contrast Checker ou com o relatório do Pa11y.WCAG Contrast Checker
Textos alternativosPasse o mouse sobre imagens e veja se o atributo alt descreve o conteúdo.Inspect Element
Tamanho de toqueEm dispositivos móveis, teste se alvos têm ao menos 44 × 44 px.Chrome DevTools (Device Mode)
Mensagens de erroSubmeta formulários com campos vazios e confirme se as mensagens são claras e associadas ao campo (aria-describedby).Formulário de teste

4.1 Exemplo de mensagem de erro acessível

<form id="loginForm" novalidate>

<label for="email">E‑mail</label> <input type="email" id="email" name="email" required aria-describedby="emailError"> <div id="emailError" class="error" hidden>Por favor, informe um e‑mail válido.</div>

<label for="senha">Senha</label> <input type="password" id="senha" name="senha" required aria-describedby="senhaError"> <div id="senhaError" class="error" hidden>Campo obrigatório.</div>

<button type="submit">Entrar</button> </form>

// validação simples

document.getElementById('loginForm').addEventListener('submit', (e) => { const email = document.getElementById('email'); const senha = document.getElementById('senha'); let valid = true;

if (!email.checkValidity()) { document.getElementById('emailError').hidden = false; email.focus(); valid = false; } else { document.getElementById('emailError').hidden = true; }

if (!senha.checkValidity()) { document.getElementById('senhaError').hidden = false; if (valid) senha.focus(); valid = false; } else { document.getElementById('senhaError').hidden = true; }

if (!valid) e.preventDefault(); });

A associação via aria-describedby garante que leitores de tela leiam a mensagem de erro imediatamente após o

Artigos relacionados