Testar cadastro de ponta a ponta sem teste instável
Equipe AltiviaCloud · 2 de setembro de 2026 · 3 min de leitura
O sleep fixo quebra dos dois lados e a caixa de e-mail compartilhada quebra em paralelo. Como esperar pela condição, e o atalho que anula o teste.
O teste de cadastro é o que mais quebra em CI e o que menos gente confia. Costuma ser vermelho por motivo errado, e por isso acaba desligado — o que é pior do que não tê-lo.
Quase sempre a causa é a mesma: o teste espera pelo relógio em vez de esperar pela condição.
O padrão que quebra
await preencherCadastro();
await clicarEmEnviar();
await esperar(5000); // <- aqui
await abrirLinkDeConfirmacao();
Esse esperar(5000) está errado dos dois lados.
Quando a entrega demora seis segundos — fila cheia, provedor lento, CI concorrido — o teste falha sem que nada esteja quebrado. Alguém investiga, não encontra nada, roda de novo, passa. O teste vira "aquele que às vezes falha", e a equipe para de acreditar nele.
Quando a entrega demora meio segundo, você desperdiça quatro segundos e meio. Multiplique por vinte testes e por trinta execuções diárias.
O padrão que funciona
Espere a condição, com um limite total:
async function esperarMensagem(caixa, limiteMs = 30000) {
const fim = Date.now() + limiteMs;
while (Date.now() < fim) {
const mensagens = await listarMensagens(caixa);
if (mensagens.length > 0) return mensagens[0];
await esperar(500);
}
throw new Error(`Nenhum e-mail chegou em ${caixa} dentro de ${limiteMs}ms`);
}
Duas diferenças que parecem pequenas e não são.
A primeira: quando a mensagem chega em quatrocentos milissegundos, o teste segue em quatrocentos milissegundos.
A segunda, e mais importante: a mensagem de erro diz o que aconteceu. "Nenhum e-mail chegou" manda quem for investigar para o lugar certo. O esperar fixo produz um "elemento não encontrado" três passos adiante, e a investigação começa na tela errada.
Isolamento: o erro que só aparece em paralelo
Times costumam criar qa@empresa.com e usar em todo teste. Funciona quando os testes rodam em fila.
No dia em que o CI passa a rodar em paralelo, o teste A lê o link de confirmação gerado pelo teste B, confirma a conta errada e falha com uma mensagem sem sentido. Pior: falha às vezes, dependendo da ordem.
A regra é: cada execução, um endereço novo. Uma caixa temporária criada sob demanda resolve, e não sobra nada para limpar depois — ela expira sozinha.
O mesmo vale para telefone. Se o cadastro exige SMS, um número virtual por execução evita a mesma colisão, e evita o chip físico numa gaveta com alguém lendo o código na mão.
O atalho que anula o teste
Ler o token direto do banco:
const token = await db.query('SELECT token FROM confirmacoes WHERE ...');
É rápido, é estável, e testa um caminho que nenhum cliente percorre. Se o disparo do e-mail quebrar, o teste continua verde — justamente o bug que ele deveria pegar.
Vale o mesmo para desligar a confirmação no ambiente de teste: o fluxo que roda em produção deixa de ser o fluxo testado.
Use o atalho de propósito, sabendo o que abriu mão, e mantenha ao menos um teste passando pelo caminho real.
O que esse teste precisa cobrir
O caminho feliz é o menos interessante. Os que pegam bug de verdade:
- Link expirado. A pessoa clica dois dias depois. Aparece mensagem clara ou erro genérico?
- Link usado duas vezes. Quebra ou avisa que já foi confirmado?
- Cadastro com e-mail já existente. E ele revela que aquele e-mail tem conta? Isso é vazamento.
- E-mail que não chega. A pessoa consegue pedir reenvio?
Um detalhe de CI
Teste que depende de rede externa falha às vezes por motivo externo. Isso é diferente de teste instável.
Distinga os dois: se a falha traz "nenhum e-mail chegou em 30s", é ambiente. Se traz "elemento não encontrado", é o seu teste.
Separar esses testes numa suíte própria, que não bloqueia o merge mas avisa, costuma ser o arranjo que sobrevive. Suíte que bloqueia por motivo externo é suíte que alguém desliga.