← React: componentes, estado e decisões de interface
09 / 10 · 65 MIN

Testar comportamentos e delimitar a evidência

Escolher consultas e interações que observam contratos de interface. Interpretar testes assíncronos, isolamento e limites de evidência sem confundir uma resposta preparada com integração real.

Começar pelo contrato observável

Antes de escolher uma biblioteca de testes, escreve a relação que queres observar. No contador, uma interação Review next deve alterar o título de zero para um. O teste não precisa de conhecer o nome da variável count nem de chamar diretamente setCount.

Seleciona o botão pelo papel e pelo nome acessível e observa o título após a interação. Assim, uma mudança de classes CSS ou de estrutura interna não obriga a alterar a intenção do teste. Isto não torna qualquer mudança irrelevante: se o botão deixar de ter um nome identificável, a consulta deve falhar e exigir análise.

Testar o contrato não significa aceitar indiscriminadamente qualquer saída.

Presença, ausência e ambiguidade

getBy procura uma correspondência atual e falha se encontrar zero ou várias. queryBy permite verificar a ausência porque devolve null perante zero correspondências, mas também falha perante várias. findBy devolve uma Promise e repete a consulta até encontrar o elemento ou atingir o limite de espera.

Nenhuma destas escolhas deve esconder a existência de dois botões Save quando o teste pretende apenas o da região de faturação. Nesse caso, delimita a região com within ou consulta um nome acessível específico, se esse for o contrato da interface.

Uma consulta singular que falha por ambiguidade está a revelar informação útil.

Interações e atualizações pendentes

user-event v14 descreve interações que podem produzir vários eventos e verificações adicionais. Cria uma instância com setup dentro do teste e aguarda os métodos assíncronos antes de afirmar o resultado. Um fireEvent isolado continua a ser útil para um evento concreto, mas não demonstra por si a sequência de foco, teclado e alteração de valor.

React fornece act para aplicar atualizações relacionadas com uma unidade de interação antes das asserções; a recomendação é a forma assíncrona com await. Os helpers de React Testing Library já integram act. Nenhum destes mecanismos inventa uma resposta de rede nem substitui a necessidade de esperar pela condição assíncrona correta.

Ler o exemplo e conservar o isolamento

ReviewCounter não comunica com um servidor: soma um ao estado local. inspectCounterContract contém a montagem, uma asserção inicial, a interação aguardada e a asserção final. O finally chama cleanup, que desmonta árvores criadas por render, incluindo quando uma asserção lança erro.

Alguns executores configuram cleanup automaticamente através de afterEach global; noutros é necessário configurá-lo. Aqui a intenção está explícita no excerto. O ambiente também precisa de DOM e transformação JSX.

Importar node:assert indica a função de inspeção no contexto de teste Node; não se deve copiar esse import para o bundle público da aplicação.

Controlar a ordem das respostas

Uma interface pode passar todos os testes em que A termina antes de B e ainda apresentar a resposta errada quando a rede inverte essa ordem. Para analisar o contrato, usa duas respostas controladas: inicia A, muda a seleção para B, resolve B e só depois A.

A observação relevante é que o resultado de B permanece associado à seleção atual. Contar dois pedidos ou dois sucessos HTTP não verifica essa propriedade. Um guard de cleanup no Effect pode impedir a aplicação de A, como na aula de sincronização.

A evidência deve distinguir rejeitar um resultado obsoleto de cancelar a operação remota, pois são contratos diferentes.

Interpretar uma simulação sem ampliar a conclusão

Considera um formulário cuja função de gravação foi substituída por uma Promise resolvida pelo teste. Ver Saved após o clique sustenta que a interface reagiu à interação e à resposta preparada. Não demonstra que um serviço real gravou os dados, que a sessão tem permissões válidas ou que o layout funciona em todos os browsers.

Da mesma forma, consultas por papel e nome ajudam a avaliar a interface, mas uma única interação não certifica acessibilidade integral. Regista o ambiente, as dependências substituídas e a asserção observada. Esta delimitação permite combinar evidências complementares sem atribuir ao teste de componente resultados que ele nunca observou.

Diagnóstico e resumo do ensaio

Perante uma falha, pergunta primeiro se o elemento devia existir agora, aparecer depois ou estar ausente. Depois verifica se a consulta tem o âmbito correto e se a interação foi aguardada. Uma pausa fixa pode fazer um teste passar ocasionalmente sem corrigir a condição observada; findBy exprime a espera por uma presença concreta com limite.

Não retires a asserção para obter uma suite verde. Por fim, confirma que árvores e recursos do caso anterior foram limpos. O resumo deve indicar o comportamento verificado e o que continua dependente de integração, browser real ou avaliação com utilizadores.

// Reading example. A JSX-capable DOM test environment is required.
// Dependencies: React, React Testing Library and user-event v14.
// Node provides assert; this is not a browser entry point.
import {useState} from 'react';
import {render, screen, cleanup} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import assert from 'node:assert/strict';

function ReviewCounter() {
  const [count, setCount] = useState(0);
  return <section>
    <h2>Reviewed: {count}</h2>
    <button type="button" onClick={() => setCount(n => n + 1)}>
      Review next
    </button>
  </section>;
}

export async function inspectCounterContract() {
  const user = userEvent.setup();
  try {
    render(<ReviewCounter />);
    assert.equal(screen.getByRole('heading', {name: 'Reviewed: 0'}).textContent,
      'Reviewed: 0');
    await user.click(screen.getByRole('button', {name: 'Review next'}));
    assert.equal(screen.getByRole('heading', {name: 'Reviewed: 1'}).textContent,
      'Reviewed: 1');
  } finally {
    cleanup();
  }
}
NA PRÁTICA

O exemplo apresenta o componente e a função de inspeção no mesmo excerto. A função aguarda o clique e verifica o título observado; finally desmonta a árvore mesmo se a asserção falhar. É um contrato de leitura para um ambiente DOM com suporte JSX, não um ficheiro executável diretamente pelo browser nem uma prova de gravação remota.

Armadilhas comuns

Usar seletores de CSS como identidade de negócio; não aguardar user.click; usar getBy para uma ausência; resolver sempre pedidos pela ordem de início; deixar árvores anteriores montadas; transformar uma simulação DOM em garantia de acessibilidade integral.

Tópicos relacionados: Formulários, contratos DOM e acessibilidade · Effects, refs e sincronização externa · Dados assíncronos, Suspense e limites de erro

Leva esta ideia contigo

Um teste útil liga uma ação a um resultado observável e declara as dependências substituídas. Consultas, sincronização e cleanup tornam essa evidência mais precisa; não aumentam automaticamente o seu âmbito para serviços, browsers ou utilizadores que não foram observados.

Criar conta

Referência: Queries, presence and scope · React 19.3.0; JSX