Testes ponta a ponta
Um teste ponta a ponta executa o aplicativo real, construído e iniciado da mesma forma que os usuários o obtêm, e o controla a partir do exterior: um navegador clicando em páginas, um shell executando uma CLI ou um cliente chamando uma API. Ele detecta o que os testes unitários não conseguem: conexões, configuração, roteamento e as junções entre as partes. Também é o tipo de teste mais lento e frágil, então cada um tem que justificar sua existência e ser escrito para dar a mesma resposta a cada execução.
A skill irmã unit-testing cobre testes de unidades individuais.
Quando um comportamento pode ser verificado em qualquer nível, verifique-o com um teste unitário.
Regras do repositório vêm primeiro
Use a estrutura, configuração, pasta, fixtures e scripts e2e do repositório. Leia os
testes existentes e a configuração (playwright.config.*, cypress.config.* e assim por diante)
antes de escrever um, e siga o mesmo padrão. AGENTS.md, CONTRIBUTING.md e os scripts
do pacote dizem como os testes e2e são executados e contra o quê. Onde eles entrarem em conflito com esta skill,
eles vencem. Não adicione uma segunda estrutura e2e.
Ferramenta padrão
Quando o repositório ainda não tem uma ferramenta e2e, use Playwright
(@playwright/test) para qualquer coisa com um navegador. Funciona para qualquer aplicativo web,
independentemente da linguagem do backend. Os exemplos aqui usam Playwright. As regras se aplicam a
qualquer ferramenta.
O que merece um teste e2e
- Jornadas críticas: cadastro, login, a tarefa principal para a qual o produto existe, checkout, e qualquer coisa que já tenha quebrado em produção.
- Pontos de integração: uma página que precisa do backend real, autenticação ou roteamento para funcionar.
- Um caminho feliz por jornada, além das falhas que um usuário realmente encontraria (uma senha errada, um pagamento recusado).
Empurre todo o resto para os testes unitários: toda regra de validação, todo caso de formatação, todo ramo de um cálculo. Uma suíte e2e que tenta cobrir todos os casos se torna lenta demais para executar e instável demais para ser confiável.
Localizadores
Encontre elementos da forma que um usuário faz, para que os testes sobrevivam a mudanças de marcação e estilo.
- Prefira, nesta ordem: role e nome acessível (
getByRole('button', { name: 'Salvar' })), label (getByLabel('Email')), texto visível e, em seguida, um ID de teste (getByTestId) quando nada voltado ao usuário for estável. - Evite: classes CSS, XPath,
nth-childe posições de elementos. Eles quebram quando o layout muda e não dizem nada sobre o que o usuário vê. - Se um elemento não puder ser encontrado por role ou label, isso geralmente é um bug de acessibilidade. Diga isso em vez de recorrer a um seletor frágil.
Espera
Nunca espere por um tempo fixo. sleep, waitForTimeout e setTimeout são muito curtos em uma
máquina de CI lenta e desperdiçam tempo em uma rápida.
- Use asserções que tentam novamente até passar ou atingir o tempo limite:
await expect(page.getByRole('alert')).toHaveText('Salvo'). - Espere pela condição que o usuário esperaria: um elemento visível, uma URL alterada, uma
resposta recebida (
page.waitForResponse), um arquivo escrito. - Não aumente os timeouts para corrigir uma falha. Se algo legitimamente demorar muito, aumente o timeout para essa etapa específica e diga o porquê.
- Não force ações além das verificações da estrutura (
{ force: true }). Se um clique precisar ser forçado, algo está cobrindo o elemento ou ele não está pronto, e um usuário real encontraria o mesmo problema.
Dados de teste e isolamento
- Cada teste configura seu próprio estado e passa sozinho, em qualquer ordem e em paralelo com os outros. Nenhum teste depende de outro ter sido executado primeiro.
- Crie dados únicos por teste (um e-mail ou ID gerado), para que workers paralelos e novas tentativas não colidam.
- Configure pelos bastidores. Crie usuários e registros por meio de uma API, um script de seed ou uma fixture, não clicando na interface. Apenas a jornada em teste passa pela interface.
- Faça login uma vez e reutilize. Salve o estado autenticado em uma etapa de configuração
(
storageStatedo Playwright) em vez de fazer login pelo formulário em todos os testes. - Falsifique apenas o que você não possui. Stub serviços de terceiros (pagamentos, e-mail, mapas) no
limite da rede com
page.route()ou um fake local. Mantenha seu próprio frontend, backend e banco de dados reais, ou não é um teste ponta a ponta.
Testes e2e de CLI e API
As mesmas regras se aplicam sem um navegador. Execute testes de CLI com o executor de testes unitários
do repositório (Vitest para JavaScript e TypeScript), em uma configuração ou projeto separado para que não diminuam
a suíte de testes unitários. Testes de API podem usar a fixture request do Playwright ou o mesmo executor.
- Execute o artefato construído, da mesma forma que os usuários o executam, não o código-fonte por meio de um ponto de entrada exclusivo para teste.
- Dê a cada teste um diretório temporário novo como seu diretório de trabalho e aponte
HOME, caminhos de configuração e caches para ele, para que os testes não leiam ou alterem os arquivos reais do desenvolvedor. - Afirme o código de saída, stdout, stderr e os arquivos criados, separadamente. Um teste que apenas verifica "não lançou exceção" perde saída incorreta.
- Remova ou congele o que muda entre execuções (timestamps, caminhos temporários, durações) antes de comparar a saída.
Quando um teste falha
Leia as evidências antes de mudar qualquer coisa.
- Obtenha os artefatos. Ative traces, screenshots e vídeo para falhas
(Playwright:
trace: 'on-first-retry',screenshot: 'only-on-failure') e abra o trace da execução do CI (npx playwright show-trace <trace.zip>). O trace mostra a página, a rede e o console em cada etapa. - Decida de quem é o bug. Se o aplicativo está errado, corrija o aplicativo; o teste fez seu trabalho. Se o teste está errado, corrija o teste. Se o ambiente está errado (um serviço fora do ar, uma porta em uso), corrija a configuração.
- Reproduza-o com o mesmo comando, navegador e configurações que o CI usa, incluindo modo headless e número de workers.
- Para um teste instável, encontre a condição de corrida. As causas usuais são: uma espera fixa, agir antes
de a página estar pronta, dados compartilhados com outro teste, ou uma animação ou toast cobrindo
o elemento. Corrija essa causa e, em seguida, execute o teste muitas vezes seguidas
(
npx playwright test <file> --repeat-each=20 --retries=0) antes de considerá-lo corrigido.
As retentativas de CI podem manter um pipeline verde, mas um teste que passou apenas na repetição ainda está falhando. Trate "instável" em um relatório como um bug a ser corrigido, não um status. Nunca pule, exclua ou coloque um teste em quarentena para ficar verde sem o acordo do usuário, e nunca afrouxe uma asserção para fazê-lo passar.
Lista de verificação
Antes de entregar testes e2e, ou ao revisá-los:
- A jornada precisa de um teste e2e. Casos que um teste unitário pode verificar são testes unitários.
- Localizadores usam role, label, texto ou um ID de teste. Sem cadeias de CSS ou XPath.
- Sem esperas fixas, ações forçadas ou timeouts globais aumentados.
- Cada teste cria seus próprios dados únicos e passa sozinho e em paralelo.
- Apenas serviços de terceiros são stubbed.
- Falhas deixam um trace ou screenshot no CI.
- O teste novo ou corrigido passou muitas vezes seguidas com as retentativas desligadas.