Teste de Contrato GraphQL
Visão Geral
Testes que se situam na costura entre camadas e quebram quando um dos lados se move sem o consentimento do outro — testes-como-controle aplicados a fronteiras. A regra cardinal: afirme sobre o contrato — a forma dos dados e as semânticas de acesso que o consumidor depende — nunca sobre a string da query em si. Um teste que quebra por uma edição cosmética na query é um anti-padrão de detector de mudanças; um teste que quebra quando a forma garantida ou permissão se move é um controle.
§1 — O Contrato de Query GraphQL
- Cada operação é criada uma vez como um documento tipado em um local conhecido, exportado para ser importado. A UI o importa; o teste importa o mesmo artefato — nunca uma cópia redigitada. Copiar uma query em um teste mata silenciosamente o contrato (editar a query da UI não quebra mais o teste). DRY tornado estrutural.
- Ele quebra em ambas as direções, por construção:
- Derivação DB → UI, em tempo de compilação.
graphql-codegengera tipos TypeScript a partir do esquema ativo. Renomeie ou remova um campo usado etscfalha em cada uso e no documento compartilhado — a build quebra antes que o usuário veja um painel vazio. É por isso que codegen contra o esquema ativo é obrigatório. - Derivação UI → DB / permissão, em tempo de execução. O documento compartilhado executa contra um banco de teste semeado através do caminho real de chamada, sob contexto de função, afirmando sobre a forma retornada e o resultado do acesso — não o texto da query.
- Derivação DB → UI, em tempo de compilação.
- Testes de contrato e a matriz de funções RLS são o mesmo harness. Execute o mesmo documento através do PostGraphile como função A (espera dados) e função B (espera negado/vazio). Um mecanismo prova três coisas: a query ainda corresponde ao esquema, as suposições da UI ainda são válidas, o RLS ainda impõe a fronteira.
Exemplo prático — como um bug real é capturado
- DB→UI: uma migração remove
equipment.is_active. Codegen regenera a partir do novo esquema; o tipo gerado perde o campo;tscfalha no documento compartilhado e em cada componente que o usa — capturado na build, antes do merge. Nenhum teste afirma "texto da query == X." - UI→DB: um desenvolvedor amplia a query da UI para puxar
cancellation_reason(RLS expõe apenas para funções elevadas). O teste de execução rodando como um membro comum afirma a forma visível ao membro, agora recebe nulo/negado, e falha — forçando "nós pretendíamos expor isso?"
§2 — Testes de Rota e Smoke Tests
- Rotas enumeradas a partir de uma única fonte. Cada rota tem um smoke test: renderiza sem erro + mostra um conjunto mínimo de elementos obrigatórios (um título, um marco, um controle chave — não interação detalhada).
- Adicionar/remover uma rota força uma mudança de teste correspondente — uma nova URL está incompleta sem seu smoke test; uma URL removida remove seu teste. URLs nunca aparecem ou desaparecem silenciosamente.
- Explícitamente NÃO é teste detalhado de UI/interação — deliberado, escopo limitado. A pergunta é "esta URL funciona e renderiza o essencial," nada mais.
Imposição: graphql-codegen + tsc no CI (bloqueante) para a parte de tempo de compilação; testes de contrato em tempo de execução + smoke tests de rota no CI contra um banco de dados semeado.
Raciocínio completo: Artigo XV da constituição, empacotado em engineering-constitution/references/engineering-constitution.md.