# Testes de Acessibilidade: WCAG e Inclusão Digital

**Meta Description:** Aprenda testes de acessibilidade: WCAG 2.1, axe-core, Lighthouse, testes manuais e como garantir que seus apps são acessíveis.

---

## Por Que Acessibilidade Importa?

- **1.3 bilhões** de pessoas com deficiência no mundo
- **Leis** como ADA, LGPD, EU Accessibility Act
- **SEO** - Google prioriza sites acessíveis
- **Reputação** - Marca inclusiva
- **Mercado** - P público que você está excluindo

---

## WCAG 2.1 - Princípios

### 4 Princípios (POUR)

| Princípio | Descrição |
|-----------|-----------|
| **Perceivable** | Informações devem ser perceptíveis |
| **Operable** | Interface deve ser operável |
| **Understandable** | Informações e interface compreensíveis |
| **Robust** | Conteúdo deve funcionar com tecnologias assistivas |

### Níveis de Conformidade

| Nível | Significado | Requisito |
|-------|-------------|-----------|
| **A** | Básico | Mínimo, deve atender |
| **AA** | Padrão | Recomendado, maioria das leis |
| **AAA** | Avançado | Mais rigoroso, poucos достигают |

---

## Ferramentas Automatizadas

### axe-core

```javascript
// Npm
npm install @axe-core/playwright

// Playwright integration
const { chromium } = require('playwright');
const AxeBuilder = require('@axe-core/playwright').default;

async function runAccessibilityTest() {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    
    await page.goto('https://example.com');
    
    const results = await new AxeBuilder({ page })
        .withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
        .analyze();
    
    console.log('Violations:', results.violations.length);
    results.violations.forEach(v => {
        console.log(`- ${v.id}: ${v.description}`);
    });
    
    await browser.close();
}
```

### Lighthouse CI

```yaml
# GitHub Actions
- name: Lighthouse
  uses: treosh/lighthouse-ci-action@v10
  with:
    urls: https://example.com
    budgetPath: ./lighthouserc.json
    uploadArtifacts: true
```

```json
// lighthouserc.json
{
  "ci": {
    "collect": {
      "settings": {
        "staticDistDir": "./dist"
      }
    },
    "assert": {
      "assertions": {
        "categories:accessibility": ["error", {"minScore": 0.9}],
        "first-contentful-paint": ["warn", { "maxNumericValue": 2000 }],
        "uses-passive-event-listeners": "off"
      }
    }
  }
}
```

---

## Testes Manuais

### Checklist de Teclado

```markdown
## Navegação por Teclado

### Essential
- [ ] Tab avança logicamente entre elementos
- [ ] Shift+Tab retorna ao elemento anterior
- [ ] Enter ativa botões e links
- [ ] Space ativa botões e checkboxes
- [ ] Escape fecha modais e dropdowns
- [ ] Setas navegam em menus

### Skip Links
- [ ] Link "Skip to main content" existe
- [ ] Link é visível quando focado
- [ ] Link funciona corretamente

### Focus Indicators
- [ ] Focus é sempre visível
- [ ] Estilo de focus não é apenas cor
- [ ] Focus não desaparece em nenhum elemento
```

### Checklist de Screen Reader

```markdown
## Screen Reader Testing

### Imagens
- [ ] Alt text em todas imagens informativas
- [ ] Alt text é descritivo e útil
- [ ] Imagens decorativas têm alt=""
- [ ] SVG complexos têm descriptions

### Formulários
- [ ] Labels associados corretamente (for/id)
- [ ] Placeholder não substitui label
- [ ] Erros anunciados
- [ ] Required fields marcados

### Heading Structure
- [ ] h1 é único na página
- [ ] Hierarquia lógica (h1 > h2 > h3)
- [ ] Sem saltos (h1 > h3, pulando h2)
- [ ] Headings não são só visuais

### Links e Botões
- [ ] Links fazem sentido fora de contexto
- [ ] Botões descrevem ação
- [ ] Links novos/abrem em nova aba avisados
```

---

## Implementando Acessibilidade

### ARIA Basics

```html
<!-- Botão com acessibilidade -->
<button 
  aria-label="Fechar modal"
  aria-expanded="false"
  aria-controls="modal-content"
>
  <span aria-hidden="true">×</span>
</button>

<!-- Modal com ARIA -->
<div 
  role="dialog" 
  aria-labelledby="modal-title"
  aria-describedby="modal-desc"
  aria-modal="true"
>
  <h2 id="modal-title">Confirmação</h2>
  <p id="modal-desc">Tem certeza que deseja excluir?</p>
  <button>Cancelar</button>
  <button>Excluir</button>
</div>

<!-- Live region para updates -->
<div aria-live="polite">
  <!-- Conteúdo atualizado dinamicamente -->
</div>

<!-- Error message -->
<label for="email">Email</label>
<input type="email" id="email" aria-describedby="email-error">
<span id="email-error" class="error" role="alert">
  Email inválido
</span>
```

### CSS para Acessibilidade

```css
/* Focus visível */
*:focus {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
}

/* Esconde visualmente mas mantém para screen readers */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}

/* Contraste adequado */
.text-primary {
  color: #1a1a1a; /* Não use #777777 com fundo branco */
}

/* Touch target mínimo */
button, a, input[type="checkbox"] {
  min-height: 44px;
  min-width: 44px;
}
```

---

## Conclusão

Acessibilidade é responsabilidade de todos. As chaves são:

1. **Testar cedo** - A11y mais barato no início
2. **Automatizar** - axe-core, Lighthouse
3. **Testar manualmente** - Teclado, screen reader
4. **Seguir WCAG** - 2.1 AA como mínimo
5. **Incluir na cultura** - A11y não é "extra"
