Skip to content

Testing Backlog — SSOT

SSOT do que falta cobrir em testes na plataforma OLP. Atualizado em cada sprint. Toda nova lacuna deve ser registrada aqui antes de virar card.

Status atual da pirâmide de testes (após Sprint P0 — CI Fix):

CamadaArquivosTestsEm CI?
Unit + Integration (Vitest src/**)76794
Deno (supabase/functions/**)85~600
Contract (tests/contracts/)1✅ (após deploy-staging)
Security/IDOR (tests/security/)poucos
E2E (Playwright)poucos

Foco notável — Resultados do Coordenador (core do produto)

Disparado pelo incidente Nível S (3º EM) reportado em 2026-06-04. Auditoria E2E em AUDIT_RESULTADOS_NIVEL_S_2026-06-04.md.

Cobertura severa de toda superfície que a tela de Resultados toca:

  • Cap silencioso 1000 do PostgREST — testar fetchAllRows (helper em _shared/pagination-helpers.ts, suite Deno já incluída) e adicionar teste de integração de gestao-resultados.list simulando >1000 inscrições para confirmar que todos os níveis aparecem em filterMeta.niveis e na contagem total. Causa raiz confirmada do incidente Nível S/J (escola com 1.4k inscrições → tela mostrava 1000 cravados → níveis do EM sumiam).
  • Pipeline de inserção (planilha + manual) — matriz 13 cenários (C1-C13), incluindo aluno sem turma, série não mapeada ao nível, divergência de nome do nível, OMU vs Canguru.
  • Mapeamento níveis↔sériesniveis_competicao_series + olimpiada_series_participantes consistência por edição.
  • Filtros de elegibilidade silenciososserieIncompativel, naoClassificadoFaseAnterior, pontuacaoMaximaPorNivel[nome] fallback null.
  • Stats por nível ativo — já mapeado em B3 do audit anterior.
  • Publicação parcial silenciosa (PFS-6) — RTL no painel de liberações: "X de Y níveis publicados", badge "pendente" por nível com resultados mas sem mural_liberacoes, exit-guard ao sair com publicação incompleta.
  • Edge fn gestao-resultados — actions: insert_lote, start_import_session, list (incluindo handleList → alunosDoNivel).

Prioridade: alta — não bloqueia outros P1, mas precede qualquer refator estrutural na feature.

Testes alvo (extraídos da §5 do audit):

  1. RTL inserir-dialog.test.tsx — matriz C1-C13.
  2. Deno gestao-resultados/__tests__/insert-lote-nivel-s.test.ts.
  3. Deno _shared/__tests__/resultados-queries-alunos-do-nivel.test.ts.
  4. E2E coordenador — fluxo completo Nível S Canguru.
  5. Contract — consistência olimpiada_series_participantes ∩ niveis_competicao_series por edição.

Foco notável — Publicação parcial silenciosa (mural)

Causa raiz confirmada do incidente Nível S (2026-06-04): planilha foi importada com sucesso (224 rows em resultados_aluno), mas o mural ficou vazio porque o coordenador publicou apenas 5 dos 6 níveis (P→E→B→C→J, S esquecido). Sem mural_liberacoes para Nível S → recomputeSnapshotsIfPublished nunca dispara → mural_dados_publicados vazio.

Cobertura necessária:

  1. RTL mural-liberacoes.test.tsx — cenário "5 níveis publicados, 1 com resultados pendente": indicador amarelo no botão do nível, badge "5 de 6 publicados" no header, modal de confirmação ao sair.
  2. Deno mural-escola/__tests__/get_liberacao_stats.cap.test.ts — escola com > 1000 resultados_aluno retorna todos os níveis distintos (risco latente do default cap PostgREST).
  3. Deno mural-escola/__tests__/get_niveis_pendentes.test.ts — novo action que cruza níveis com resultados × liberações.
  4. E2E coordenador — publicar Canguru com 6 níveis e verificar que portal mostra todos.

Prioridade: alta — risco de repetir o incidente em qualquer escola com olimpíadas de 3+ níveis.


Sprint corrente — Webhooks (P0+1)

ItemTipoStatus
resend-webhook — HMAC + tolerance window + idempotência + bounce/complained → unsubscribeDeno black-box contra staging🔄 em andamento
wasender-webhook — HMAC + idempotência + status mapping + rate limitDeno black-box⬜ todo
mercadopago-webhook — adicionar contract test de assinatura ts/v1 + tipos payment.* e subscription_preapprovalDeno (existe base)⬜ todo
WEBHOOK_TESTING_STANDARD.md — padrão SSOT de teste de webhookDoc🔄
Memória mem://testing/webhook-contract-standardMemory

Definição de pronto da sprint: 3 webhooks com suite Deno completa, CI verde, doc + memória publicadas.


P1 — Anti-regressão crítica (próximas 2–3 sprints)

Hooks useAdmin* (8 hooks sem teste)

HookCobertura mínima
useAdminDashboardrender + queryKey contém escola_id + onError sanitiza
useAdminLogsfiltros (acao, periodo) + paginação
useAdminFinanceiromutations + optimistic rollback
useAdminFaturaslistagem + ações de cobrança
useAdminComunicacaoenvio + audiência
useAdminEscolasCRUD escola
useAdminUsuariosCRUD usuário + escopo de papel
useAdminRelatoriosfiltros e export

Edge Functions sem teste (P1)

FunctionRiscoTests obrigatórios
admin-dashboardleitura ampla — IDORauth, IDOR cross-escola, shape do payload
admin-logsPIImasking, filtros, IDOR
admin-financeirodinheiroIDOR, mutações com 403 em zero rows
admin-comunicacaoenvio de massarate limit, audiência, IDOR
admin-faturasdinheiroIDOR, idempotência de cobrança

IDOR coverage tests/security/

Para cada função admin-* acima: teste cross-escola provando 403 quando JWT de escola A tenta acessar recurso de escola B.

Sanitização de erros

Adicionar fixtures de erros Postgres reais (23505, 23503, 42501, PGRST*) ao suite unit de error-helpers.ts garantindo que nenhuma jargão técnica vaza pra UI.

Smoke RTL das páginas admin (10 páginas)

Render sem crash + presença do título + ausência de erros no console.


P2 — Cobertura de feature

Hooks restantes (46 sem teste — 57% do total)

Priorizar por:

  1. Hooks que fazem mutação (rollback, toast, queryKey invalidation)
  2. Hooks com derived data complexa (memo + filter)
  3. Hooks de Mural Olímpico (alto risco LGPD)

Edge Functions sem teste (~15)

  • mural-* (6 funções): OTP, login, snapshot, releases
  • portal-*: gateway, redirect
  • import-*: validação Excel + processamento background

Contratos externos (Contract suite)

ProviderCenário
Twilio (SMS)retry, falha 4xx, custo > 0
Cloudflare Worker (gateway)redirect whitelisted, anti-loop
Resend (transactional)já coberto via webhook — falta envio

E2E flows críticos (Playwright)

  • Login (CPF/INEP/CNPJ) + OTP + role switch
  • Criação de aplicação pelo coordenador
  • Aprovação de inscrição pelo especialista
  • Ciclo trial → pagamento MP → fatura paga

P3 — Qualidade transversal

ItemFerramentaGate
Performance budgets (LCP/TBT)Lighthouse CILCP < 2.5s nas rotas top-5
Acessibilidade A11yaxe-core + PlaywrightZero violações serious/critical
Visual regressionPlaywright snapshotsTelas admin + portal
Cobertura mínimaVitest coverage≥ 60% global, ≥ 80% em lib/ e _shared/

P4 — Observabilidade do CI

  • Upload de coverage (Codecov ou artifact persistente)
  • Badge no README
  • Tempo por job + alerta >10min
  • Mutation testing (Stryker) em _shared/ e src/lib/

Métricas de saída (definição de pronto do backlog)

MétricaHojeMeta
Edge Functions com teste74%100%
Hooks com teste43%≥ 80%
Páginas com smoke test0%100%
Contratos externos com suite1/55/5
Cobertura IDOR admin-*parcial100%
Cobertura global (Vitest + Deno)desconhecida≥ 60%

Backlog de Features (produto)

✅ Boleto Bancário Mercado Pago — CONCLUÍDO (2026-06-17)

Entrega original (2026-06): emissão automática via CRON + manual via UI escola/admin, adapter createBoleto/cancelBoleto em _shared/payment-gateway.ts, edge function mercadopago-boleto (actions gerar/cancelar), hook useMercadoPagoBoleto, campos boleto_* em escola_faturas, doc canônica em features/billing/boleto-manual.md.

Cobertura de testes entregue:

CamadaArquivoCenários
SSOT régua (front+edge)src/lib/__tests__/cobranca-regua.test.ts + supabase/functions/_shared/__tests__/cobranca-regua.test.tsD+3/D+10/D+17, paridade
Adaptersupabase/functions/_shared/__tests__/payment-gateway-boleto.test.tsPayload bolbradesco, idempotency-key, vencimento BRT, erros 400/401/429
Edge fn (contract)supabase/functions/mercadopago-boleto/__tests__/index.test.tsCORS, 401 auth, action inválida, GET 405
Edge fn (IDOR)tests/security/idor-mercadopago-boleto.test.tsCross-escola 403 (gerar/cancelar)
CRON backgroundsupabase/functions/faturamento-cron/__tests__/boleto-background.test.tsSkip CNPJ, skip endereço, skip migrada/pago, skip já-tem-boleto, sucesso → log boleto_emitido
Webhooksupabase/functions/mercadopago-webhook/__tests__/boleto-bolbradesco.test.tsNotificação de boleto rejeitada por HMAC (security)
Hook UIsrc/hooks/__tests__/useMercadoPagoBoleto.integration.test.tsxgerar/cancelar + invalidação cache + forcar=true
E2E (gated)e2e/billing-boleto.spec.tsEscola gera boleto; admin reemite/cancela via drawer (BILLING_E2E_ENABLED=1)

Lacunas remanescentes (não bloqueiam — registrar como P3):

  • RTL completo de pagamentos-escola.tsx (655 linhas, ~12 hooks) e escola-drawer.tsx (admin) — esforço alto vs ganho marginal (lógica de boleto já coberta por hook + adapter
    • E2E). Tratar quando feature for refatorada.
  • Happy path real do adapter contra MP sandbox (custo $$, fica fora de CI).

Ref: SSOT em features/billing/boleto-manual.md, memória mem://features/billing/boleto-manual-ui-backlog.


Como contribuir com este backlog

  1. Encontrou superfície sem teste? Adicione linha à tabela P1/P2/P3 conforme criticidade.
  2. Concluiu item? Mover para ## Histórico no final + atualizar Métricas.
  3. Mudou prioridade? Atualizar com nota decisão YYYY-MM-DD: motivo.

Este arquivo é referenciado em:

  • docs/development/TESTING_MASTER.md (seção "Backlog")
  • docs/development/AUDIT.md (@audit testes)
  • Sidebar: Testes > Backlog

Billing — Boleto Manual (triagem 2026-06-20)

Cards abertos a partir da triagem dos itens fora de escopo do MVP. Detalhe em docs/features/billing/boleto-manual.md §Roadmap pós-MVP.

  • B-BOL-1 (P2) — Feriados nacionais no D+3: tabela feriados_nacionais + helper SSOT feriados-br.ts (front+edge); cobertura com véspera de Natal, Carnaval (móvel via Gauss), feriado em sábado. Roadmap: mem://features/billing/feriados-dias-uteis-roadmap.
  • B-BOL-2 (P2) — Histórico append-only de boletos por fatura: tabela escola_fatura_boleto_historico + persistência em todo gerar/cancelar; pré-requisito para ADR-017. Testes: persistência multi-emissão, IDOR cross-escola, query helper.
  • B-BOL-3 (P2) — Refund de boleto pago: action reembolsar separada de cancelar; adapter refundPayment no payment-gateway.ts; webhook idempotente para evento refunded. Testes: adapter, edge contract, IDOR, webhook idempotência.
  • B-BOL-4 (P3) — Rate limit por escola em gerar: reusar portal_rate_metrics; default N=5/min/escola. Teste: 6ª chamada em 60s retorna 429 com Retry-After.
  • B-BOL-5 (P2, gated ADR-017) — Override de valor pelo admin: 6 testes obrigatórios listados em ADR-017 §2.7. Não criar testes antes do ADR ser aceito.

Histórico

  • 2026-05-09 — Incidente CI (deno-tests + security-tests): 477 falhas Deno + 1 falha security tests classificadas em AUDIT_TEST_BREAKAGE_2026-05-09. Corrigidos: env do step deno-tests (passada via secrets STAGING_*), pdf-helpers-xss.test.ts movido para suite jsdom. Em aberto: D1 (fallback hardcoded em e2e-login.contract.test.ts), D2 (reavaliar 401 antes de Zod após CI verde), D3 (helper requireEnv). Confirmado: OLP não depende de Node 20 (CI em Node 22).
  • 2026-05-09 — Sprint P0 (CI Fix) concluída: 794 Vitest tests + 600 Deno tests agora rodam em CI (antes só 4 sentinelas). getUserFriendlyError ganhou padrões para Postgres/PGRST/connection. Modais de senha alinhados ao SSOT "Sua segurança importa".