Construtor de Testes Automatizados
Objetivo: testes que falham apenas quando o produto está quebrado, e que contam o motivo em um relance.
Antes de escrever código
- Encontre a configuração existente:
playwright.config.*,pytest.ini/pyproject.toml, fixtures, helpers, page objects, dados de teste. Estenda o que já existe. Não adicione um segundo framework. - Escolha o caso de origem. Se não houver nenhum, escreva o caso primeiro (passos e resultado esperado) na descrição do teste, depois o código.
- Decida a camada. Use a camada mais barata que ainda detecte o bug:
| O que você quer provar | Camada |
|---|---|
| Regra de negócio, validação, permissões | Teste de API |
| Um usuário consegue concluir um fluxo na UI real | Um teste E2E por fluxo |
| Renderização de um componente em muitos estados | Teste de componente, se o projeto os tiver |
| Os dados realmente mudaram | Verificação via API ou DB após o passo de UI |
Se o projeto ainda não tem framework, comece com Playwright Test para web e API, e
pytest + requests para um serviço Python. Mantenha o primeiro commit pequeno: configuração, uma fixture,
um teste que passa, um job de CI.
Localizadores
Prefira, nesta ordem:
getByRole(role, { name }), que também é uma verificação de acessibilidade.getByLabel,getByPlaceholder,getByTextpara texto estático.getByTestIdquando o markup não é semântico. Peça aos devs para adicionardata-testidem vez de usar caminhos CSS.
Nunca use XPath por índice, nomes de classe gerados automaticamente, ou nth() sem um motivo em um comentário.
Esperas
- Não use
waitForTimeoutousleep. Espere por um estado:await expect(locator).toBeVisible(),page.waitForResponse(url), ou um poll na API (expect.poll). - Asserções no Playwright repetem. Use
expect(locator)em vez de ler texto e comparar. - Se algo é lento por design (email, fila), faça poll com um timeout e uma mensagem clara.
Dados de teste e estado
- Crie o que o teste precisa através da API em uma fixture, e limpe depois.
- Dados únicos por execução: sufixo com um timestamp ou
test.info().workerIndex. - Faça login uma vez por papel usando
storageState, não pela UI em cada teste. - Nunca dependa da ordem entre testes. Cada teste deve passar sozinho com
--grep.
Estrutura
tests/
api/ verificações rápidas de regras e permissões
e2e/ fluxos de usuário, poucos e importantes
fixtures/ autenticação, construtores de dados, cliente de API
pages/ page objects apenas quando uma página é usada por 3+ testes
Nomeie os testes como comportamento: viewer cannot delete a project, não test_delete_3.
Um comportamento por teste. Várias linhas de expect são aceitáveis quando descrevem aquele único comportamento.
Exemplos em examples/: um fluxo de UI com setup via API, um teste de permissão de API, e uma versão pytest.
Terceiros e efeitos colaterais
Stub os provedores de pagamento, email, analytics e mapas com page.route ou um test double, a menos que o
teste seja sobre essa integração. Marque testes de integração real com uma tag (@integration) para que o CI possa
rodá-los separadamente.
Desflakificar um teste
- Reproduza:
npx playwright test <arquivo> --repeat-each=20 --workers=4. - Abra o trace (
--trace on) de uma execução falha e encontre o primeiro passo que difere de um sucesso. - Causas comuns: uma espera fixa, um localizador que corresponde a dois elementos, dados compartilhados entre workers, animação, uma requisição que termina após a asserção.
- Corrija a causa. Retries no CI são uma rede de segurança, não uma correção. Nunca marque um teste como ignorado sem um link de ticket no motivo da ignorância.
Definição de pronto
- O teste passa sozinho e na suíte completa, três execuções consecutivas.
- Você o viu falhar: quebre a asserção ou o estado do app uma vez e verifique se a mensagem de falha faz sentido.
- Nenhum segredo no código. Credenciais vêm de variáveis de ambiente.
- O nome do teste, o ID do caso (em uma anotação ou tag) e o resultado esperado são legíveis no relatório.
Relate de volta: arquivos alterados, como executá-los, o que os testes cobrem, e qualquer coisa que você não pôde automatizar e por quê.