Skip to content

Playbook de Erros E2E — OLP

SSOT para resolução de erros em testes. Toda falha encontrada DEVE ser catalogada aqui com causa raiz, classificação e padrão derivado.

Última atualização: 2026-04-04


1. Protocolo de Diagnóstico

Workflow obrigatório antes de classificar qualquer falha de teste:

text
┌─────────────────────────────────────────────────────┐
│  1. Rodar o teste contra PRODUÇÃO no sandbox        │
│     BASE_URL=https://olp.digital npx playwright ... │
│                                                     │
│  2. Passou em prod?                                 │
│     ├─ SIM → Teste está correto.                    │
│     │        Problema é no staging (dados/infra).   │
│     │        → Corrigir staging, NÃO o teste.       │
│     │                                               │
│     └─ NÃO → Bug no teste (seletor, import, lógica)│
│              → Corrigir o teste, catalogar aqui.    │
│                                                     │
│  3. NUNCA relaxar assertions para aceitar           │
│     resultados vazios ou incorretos.                │
└─────────────────────────────────────────────────────┘

Checklist antes de dar veredito

  • [ ] Teste rodou contra produção?
  • [ ] DOM real foi inspecionado (browser tools ou screenshot)?
  • [ ] Se falha é timing: qual é o tempo real da operação em staging?
  • [ ] Se falha é dados: staging tem os mesmos dados que produção?
  • [ ] Se falha é seletor: seletor bate com o DOM real em produção?

2. Catálogo de Erros e Resoluções

ERR-001 — ReferenceError: BASE_URL is not defined

CampoValor
Arquivoe2e/loading-gate.spec.ts
ErroReferenceError: BASE_URL is not defined (3 testes falharam)
Causa raizImport faltando — o spec importava apenas TIMEOUTS mas usava BASE_URL
ClassificaçãoBug de teste (import)
ResoluçãoAdicionar BASE_URL ao import: import { BASE_URL, TIMEOUTS } from './fixtures/constants'
Padrão derivadoTodo spec que usa navegação DEVE importar BASE_URL de fixtures/constants

ERR-002 — waitForURL timeout após login em SPA

CampoValor
Arquivoe2e/login-senha.spec.ts
Erropage.waitForURL(regex) expira mesmo com login bem-sucedido
Causa raizSPA não muda a URL após login — o React Router renderiza o Dashboard na mesma rota
ClassificaçãoBug de teste (premissa errada sobre navegação SPA)
ResoluçãoSubstituir waitForURL por page.waitForSelector('nav button') para verificar que o Dashboard hidratou
Padrão derivadoEm SPAs, nunca usar waitForURL para confirmar login. Verificar a presença de elemento do Dashboard (sidebar/nav)

ERR-003 — Seletor input[name="senha"] não encontrado

CampoValor
Arquivoe2e/login-senha.spec.ts
Errolocator.fill: Error: strict mode violation ou element not found
Causa raizO input de senha no DOM real usa id="senha" sem atributo name
ClassificaçãoBug de teste (seletor errado)
ResoluçãoCorrigir seletor para input#senha
Padrão derivadoPreferir seletores #id sobre [name]. Sempre inspecionar o DOM real em produção (browser tools ou screenshot) antes de criar seletores

ERR-004 — Toggle de senha não funciona com click()

CampoValor
Arquivoe2e/login-senha.spec.ts
ErroApós click() no botão de toggle, o input continua type="password"
Causa raizO componente usa padrão hold-to-reveal (mousedown mostra, mouseup esconde) em vez de toggle simples
ClassificaçãoBug de teste (premissa errada sobre interação)
ResoluçãoUsar dispatchEvent('mousedown') para revelar e dispatchEvent('mouseup') para ocultar
Padrão derivadoVerificar o padrão de interação real do componente (click vs hold vs hover) antes de escrever o teste. Testar manualmente no browser primeiro

ERR-005 — Login timeout 15s insuficiente

CampoValor
Arquivoe2e/fixtures/constants.ts
ErroLogin expira antes de completar no staging
Causa raizArgon2id (hash de senha) é computacionalmente caro por design. No staging com menos recursos, pode levar >15s
ClassificaçãoStaging infra (timing)
ResoluçãoAumentar TIMEOUTS.login de 15s para 30s
Padrão derivadoTIMEOUTS.login DEVE ser ≥30s. Para cold start de Edge Functions, usar ≥20s. Timeouts devem considerar o pior caso do staging, não o caso médio de produção

ERR-006 — Templates não carregam ao clicar olimpíada (hook)

CampoValor
ArquivoComponente de templates do especialista/coordenador
ErroLista de templates sempre vazia ao selecionar olimpíada
Causa raizHook deprecated retornava [] as Template[] hardcoded. O listarTemplates() imperativo populava o cache do React Query, mas o componente lia a propriedade estática vazia
ClassificaçãoBug de código (hook deprecated, não reativo)
ResoluçãoUsar hook reativo (useComunicacaoTemplates(hubId)) que lê diretamente do cache React Query
Padrão derivadoSe dados não aparecem na UI, verificar se o hook lê do cache React Query de forma reativa (subscription). Hooks imperativos que populam cache sem retornar dados são anti-padrão

ERR-007 — Templates vazio no staging (dados)

CampoValor
ArquivoSeed/dados do staging
ErroTeste de comunicação falha porque não há templates associados à escola de teste
Causa raizO seed do staging não incluía dados de template_hubs e templates_mensagem para a escola "Monteiro Lobato"
ClassificaçãoStaging dados (seed incompleto)
ResoluçãoAdicionar templates ao seed do staging
Padrão derivadoSe o teste espera dados (templates, olimpíadas, alunos), o seed do staging DEVE ter esses dados. Nunca aceitar empty state como correto se produção tem dados

ERR-008 — Notificação ntfy nunca enviada no CI

CampoValor
Arquivo.github/workflows/ci.yml
ErroStep "Notificar falha E2E via ntfy" termina em 0s sem enviar nada, sem erro visível
Causa raizWorkflow usava secrets.NTFY_TOPIC mas o secret no GitHub se chama NTFY_TOPIC_URL. Variável vazia → if [ -n ] falha silenciosamente
ClassificaçãoBug de infra (nome de secret divergente entre Supabase e GitHub Actions)
ResoluçãoTrocar para secrets.NTFY_TOPIC_URL, adicionar warning explícito se ausente, e aceitar tanto hash quanto URL completa
Padrão derivadoNomes de secrets entre ambientes (Supabase Vault vs GitHub Actions) podem divergir. Sempre validar com log/warning se o secret está vazio antes de usá-lo. Nunca assumir que ausência de erro = execução bem-sucedida

ERR-009 — Seletor .cursor-pointer genérico causa clique em elemento errado

CampoValor
Arquivoe2e/comunicacao-coordenador.spec.ts
ErroTeste "clicar em olimpíada carrega templates" falha — clica em elemento errado ou não encontra card
Causa raizSeletor [data-testid="olimpiada-card"], .cursor-pointer — o data-testid nunca foi adicionado ao componente, e .cursor-pointer é genérico demais (casa com checkboxes, labels, skeletons)
ClassificaçãoBug de teste (seletor) + Bug de código (data-testid ausente)
ResoluçãoAdicionar data-testid="olimpiada-card" no componente comunicacao-templates.tsx e usar apenas [data-testid="olimpiada-card"] no teste
Padrão derivadoComponentes interativos clicados por E2E DEVEM ter data-testid. Nunca usar classes CSS utilitárias (.cursor-pointer, .flex, etc.) como seletor principal

3. Padrões Derivados — Checklist

Regras consolidadas extraídas do catálogo. Obrigatórias para testes novos e revisão de existentes.

3.1 Seletores

  • [ ] Preferir #id sobre [name] ou [data-testid]
  • [ ] Inspecionar DOM real em produção antes de definir seletores
  • [ ] Nunca assumir que atributo name existe — verificar
  • [ ] Para formulários: usar o id do input que está no htmlFor do label

3.2 Navegação SPA

  • [ ] Não usar waitForURL para confirmar login ou navegação interna
  • [ ] Verificar hidratação via presença de elemento do Dashboard (nav button, sidebar)
  • [ ] Usar waitUntil: 'domcontentloaded' em vez de 'load' (evita espera por polling/realtime)

3.3 Timing

  • [ ] TIMEOUTS.login ≥ 30s (Argon2id)
  • [ ] Cold start Edge Functions ≥ 20s
  • [ ] Considerar pior caso do staging, não média de produção
  • [ ] Se timeout falha, medir tempo real antes de aumentar arbitrariamente

3.4 Interações

  • [ ] Verificar padrão de interação real (click vs hold vs hover vs drag)
  • [ ] Testar manualmente no browser antes de escrever automação
  • [ ] Para hold-to-reveal: usar mousedown/mouseup
  • [ ] Para dropdowns shadcn: usar click + waitForSelector no popover

3.5 Dados e Staging

  • [ ] Se teste espera dados, seed do staging DEVE ter esses dados
  • [ ] Nunca aceitar empty state se produção tem dados — corrigir seed
  • [ ] Validar que escola/usuário de teste tem as relações necessárias (olimpíadas, templates, turmas)

3.6 Hooks e React Query

  • [ ] Se dados não renderizam, verificar se hook é reativo (subscription do React Query)
  • [ ] Hooks imperativos que populam cache sem retornar dados são anti-padrão
  • [ ] Após fix em hook, rodar teste E2E para confirmar que dados aparecem

4. Como Adicionar Novo Erro

Ao encontrar uma nova falha de teste:

  1. Seguir o Protocolo de Diagnóstico (Seção 1)
  2. Criar entrada no Catálogo (Seção 2) com o próximo ID sequencial (ERR-008, etc.)
  3. Preencher todos os campos: Arquivo, Erro, Causa raiz, Classificação, Resolução, Padrão derivado
  4. Adicionar padrão à checklist da Seção 3 se for uma regra nova
  5. Atualizar a data no cabeçalho do documento

Template para nova entrada

markdown
### ERR-XXX — [Descrição curta]

| Campo | Valor |
|-------|-------|
| **Arquivo** | `e2e/xxx.spec.ts` |
| **Erro** | [Mensagem de erro exata] |
| **Causa raiz** | [O que realmente causou] |
| **Classificação** | Bug de teste / Staging infra / Staging dados / Bug de código |
| **Resolução** | [O que foi feito para corrigir] |
| **Padrão derivado** | [Regra para testes futuros] |

ERR-010 — password-history-helper.test.ts regex desatualizada

CampoValor
Arquivosupabase/functions/_shared/password-history-helper.test.ts
ErroassertExists(match) falha — match é null
Causa raizConstante renomeada de HISTORY_LIMIT para HISTORY_SAVE_LIMIT + HISTORY_CHECK_LIMIT durante refatoração. Teste usa regex readTextFile e ficou desatualizado.
ClassificaçãoBug de teste (regex)
ResoluçãoAtualizar regex para HISTORY_SAVE_LIMIT e valor esperado 5
Padrão derivadoTestes que fazem parse de source code via regex devem ser atualizados junto com renomeações de exports

Referências