Especialização Frontend com React & TypeScript • React 19, Hooks, Estado Global e Next.js


🗺️ Mapa Conceitual do Tópico

flowchart TD
    TEST["Teste RTL (Simula Usuário Real)"] --> QUERY["screen.getByRole('button', { name: /salvar/i })"]
    QUERY --> EVENT["await user.click(button)"]
    EVENT --> ASSERT["expect(screen.getByText(/sucesso/i)).toBeInTheDocument()"]

🏛️ 1. A Filosofia da React Testing Library (RTL)

A React Testing Library revolucionou os testes de interface ao abandonar os testes de detalhes de implementação (como inspecionar o estado interno ou os métodos de classe) em favor de testar a aplicação exatamente da mesma forma que o usuário final e a tecnologia assistiva interagem com ela:

“The more your tests resemble the way your software is used, the more confidence they can give you.”


🎯 2. Hierarquia de Prioridade das Queries de Busca

Para maximizar a acessibilidade e a robustez dos testes contra refatorações de markup, siga a ordem de preferência oficial da RTL:

  1. Queries Acessíveis a Todos (Prioridade Máxima):
    • getByRole: Busca por papel semântico (button, heading, checkbox, dialog).
    • getByLabelText: Busca campos vinculados a labels.
    • getByPlaceholderText: Busca por placeholders de input.
    • getByText: Busca por textos visíveis na tela.
  2. Queries Semânticas:
    • getByAltText: Busca imagens por texto alternativo.
    • getByTitle: Busca por títulos de atributo.
  3. Escotilha de Fuga (Escape Hatch):
    • getByTestId: Utilizar apenas quando o elemento não possuir representação semântica ou papel acessível no DOM.

📊 3. Comparativo: Vitest vs Jest

Recurso Vitest (Moderno) Jest (Legado)
Integração com Vite ✅ Nativa (compartilha a mesma config) ❌ Requer configuração duplicada
Suporte Nativo a ESM ✅ Nativo e transparente ⚠️ Problemático e exige flags
Velocidade de Execução Ultrarrápida com workers multithread Mais pesada em cold start
Compatibilidade de API 100% compatível com a API de describe/it/expect Padrão histórico

⚠️ 4. Armadilhas Comuns e Anti-Padrões de Produção

  1. Uso de fireEvent em vez de userEvent: O fireEvent dispara apenas o evento sintático direto, ignorando a sequência natural de foco, clique e teclado que o navegador executa. Use sempre @testing-library/user-event.
  2. Esquecer de await em Chamadas de userEvent: Todos os métodos do userEvent moderno são assíncronos. Esquecer o await gera testes com falsos positivos (flaky tests).

💡 5. Diretrizes de Engenharia (Meta & React Docs)

  • Evite Testar Detalhes de Implementação: Não teste se um hook específico foi invocado ou qual é o valor exato de uma variável de estado interna. Teste o que aparece ou desaparece visualmente na tela após a ação do usuário.
  • Prefira Asserções com jest-dom: Utilize matchers expressivos como .toBeInTheDocument(), .toBeDisabled() e .toHaveValue().

💻 6. Demonstração Arquitetural do Conceito

// ToggleComponent.test.tsx - Teste acessível e robusto
import React, { useState } from "react";
import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

function VisibilityToggle() {
  const [visible, setVisible] = useState(false);
  return (
    <div>
      <button onClick={() => setVisible(v => !v)}>Alternar</button>
      {visible && <p>Conteúdo confidencial exibido.</p>}
    </div>
  );
}

describe("VisibilityToggle", () => {
  it("deve alternar a visibilidade do conteúdo ao clicar no botão", async () => {
    const user = userEvent.setup();
    render(<VisibilityToggle />);

    expect(screen.queryByText(/conteúdo confidencial/i)).not.toBeInTheDocument();

    await user.click(screen.getByRole("button", { name: /alternar/i }));
    expect(screen.getByText(/conteúdo confidencial/i)).toBeInTheDocument();
  });
});

📋 7. Cheat-Sheet das Variantes de Query da RTL

Variante Quando o elemento não existe? Suporta Assíncrono? Quando Utilizar?
getBy... Lança Exceção ❌ Não Elementos que obrigatoriamente devem estar na tela.
queryBy... Retorna null ❌ Não Assertar que um elemento NÃO deve estar na tela.
findBy... Rejeita Promise ✅ Sim (await) Elementos que surgem após chamadas assíncronas/APIs.

🔍 8. Diagnóstico de Performance & React DevTools Profiler

Velocidade e cobertura no pipeline:

  • Tempo de Execução: Suites de teste com Vitest e happy-dom executam em menos de 10ms por arquivo de teste.
  • Relatório de Cobertura V8: Execute vitest --coverage para inspecionar branches e linhas não cobertas diretamente no terminal.

🧪 9. Casos de Teste e Cenários de Borda Recomendados

  • 🔍 Elementos Ocultos no DOM: Valide a diferença entre elementos presentes com display: none vs elementos desmontados.
  • 🔍 Simulação de Digitação Longa: Teste o preenchimento de inputs com strings longas para avaliar a performance do userEvent.
  • 🔍 Asserções em Modais: Valide o fechamento de modais tanto pelo botão de fechar quanto pelo clique no backdrop e tecla Esc.