Melhores Práticas de Teste
Um resumo condensado das 25 melhores práticas mais importantes, extraídas de todas as páginas desta seção.
Busque em todas as páginas da documentação
Um resumo condensado das 25 melhores práticas mais importantes, extraídas de todas as páginas desta seção.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
getByRole → getByLabelText → getByText → getByTestId) para que as asserções correspondam à árvore de acessibilidade; usar getByTestId primeiro acopla os testes à implementação e perde regressões de acessibilidade.getBy* lança um erro para zero correspondências e findBy* tenta novamente, portanto, apenas queryBy* é seguro para asserções de "não deve existir" - usar getBy* para ausência gera um erro confuso de "não encontrado" em vez de uma asserção falha limpa.within(listItem) (ou um aria-label com nome exclusivo) para que você atinja exatamente a linha que deseja, em vez da primeira correspondência na página.userEvent (v14+) retorna uma Promise, portanto, esquecer await permite que a próxima asserção seja executada antes que o evento seja processado e transforma testes falhos em passes silenciosos e falsos positivos - sempre await userEvent.click(button).userEvent.type dispara a sequência completa de foco → keydown → keypress → input → keyup, que é o que componentes reais e validadores escutam; fireEvent.change apenas define o valor e pula os eventos de pressionamento de tecla dos quais bibliotecas como React Hook Form dependem.createJestConfig do next/jest para que as transformações SWC, mocks de CSS-module e resolução de env/alias ciente de next.config.js sejam gratuitas; coloque os matchers do jest-dom em setupFilesAfterSetup (não setupFiles) ou as extensões expect não estarão no escopo.@vitejs/plugin-react para JSX, environment: "jsdom", globals: true, uma importação de @testing-library/jest-dom/vitest no arquivo de configuração e "vitest/globals" em tsconfig.compilerOptions.types - se faltar um deles, os tipos JSX ou de matcher falharão silenciosamente.vi.mock() é içado acima das importações, portanto, as variáveis declaradas no corpo do módulo são undefined dentro da fábrica; use vi.hoisted(() => ({ mockPush: vi.fn() })) e referencie essa referência compartilhada tanto da fábrica quanto de seus testes.vi.clearAllMocks() (ou jest.clearAllMocks()) em beforeEach; o mesmo se aplica a vi.restoreAllMocks() para spies e server.resetHandlers() para MSW.findByRole / findByText quando estiver esperando um elemento aparecer e waitFor apenas quando a asserção não for sobre um elemento (por exemplo, a contagem de chamadas de um efeito colateral) - findBy encapsula a retentativa e fornece melhores mensagens de erro.waitFor pesquisa seu callback a cada ~50ms, portanto, colocar userEvent.click() ou um spy de fetch dentro dele dispara o evento repetidamente e corrompe o estado; faça a interação fora de waitFor e mantenha apenas as asserções dentro.server.resetHandlers() em afterEach para que os overrides por teste não vazem para o próximo teste e mantenha onUnhandledRequest: "error" para que qualquer endpoint esquecido apareça imediatamente em vez de mascarar como um travamento misterioso.useCartStore.setState({ items: [] }) (ou getState().reset()) em beforeEach - caso contrário, as mutações de um teste preenchem o próximo de forma invisível.QueryClient com retry: false dentro de um helper renderWithProviders para cada teste; um cliente compartilhado armazena em cache as respostas entre os testes e trava as suítes em retentativas falhas.role="alert" para que sejam anunciados por leitores de tela e consultáveis como await screen.findAllByRole("alert"); lembre-se que o React Hook Form valida no submit por padrão, então asserir erros antes do submit não encontra nada, a menos que você defina mode: "onChange".useActionState não pode realmente executar uma Server Action sob jsdom, portanto, simule o hook para retornar uma tupla controlada [state, formAction, isPending] ao testar UI de erro/pendente de formulário - testar a ação real pertence a um teste de integração Node/Vitest.renderHook, qualquer chamada síncrona que acione uma atualização de estado precisa de act(() => result.current.increment()) ou você receberá um aviso mais um result.current obsoleto; sob timers falsos, também avance dentro de act ou passe { shouldAdvanceTime: true }.result.current é uma referência viva que muda após cada renderização, portanto, const { count } = result.current captura um snapshot que fica obsoleto - sempre leia result.current.count diretamente em cada asserção.render() não aceita uma Promise, portanto, teste Server Components assíncronos chamando-os como funções e aguardando o JSX: const ui = await PostList({ id: "1" }); render(ui); - passar o componente diretamente lança um erro.cookies(), headers(), revalidatePath e revalidateTag lançam erros fora do contexto de requisição do Next.js, portanto, substitua-os com vi.mock("next/headers", …) e vi.mock("next/cache", …) - também simule notFound() para lançar um erro sentinela para que await expect(fn()).rejects.toThrow() funcione.page.getByRole, getByLabel e getByText em vez de seletores CSS e encapsule-os em classes de Page Object; seletores CSS como .btn-primary.mt-4 quebram no instante em que alguém renomeia uma classe.expect() do Playwright tentam novamente automaticamente por até 5 segundos, portanto, await expect(page).toHaveURL("/dashboard") substitui todos os page.waitForTimeout(500) - sleeps codificados são a principal fonte de testes E2E instáveis.webServer em playwright.config.ts para iniciar o Next.js automaticamente com reuseExistingServer: !CI e habilite trace: "on-first-retry" para que execuções falhas enviem uma linha do tempo completa de DOM/rede/console que você pode abrir com playwright show-trace.setup mais storageState: "e2e/.auth/user.json" para que cada teste comece logado sem o custo de login, e registre os mocks page.route() antes de page.goto() - rotas definidas após a navegação perdem o carregamento inicial da página.Revisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥