Envolver uma assertion do Playwright em try/catch silencia a falha: o teste passa quando não deveria, e o bug vai para produção. O finally garante limpeza mesmo quando o teste falha. Mensagens throw customizadas tornam erros de setup mais fáceis de diagnosticar do que falhas genéricas de assertion.
O básico: try/catch
Um bloco try/catch permite rodar código e tratar erros sem travar o programa:
try {
// Código que pode lançar um erro
const resultado = JSON.parse('json inválido');
} catch (error) {
// Isso roda se o bloco try lançar um erro
console.log('Parsing falhou:', error.message);
}Sem try/catch, JSON.parse('json inválido') travaria o script com um erro não tratado. Com try/catch, você trata com controle.
A variável error no bloco catch é o objeto Error, que tem:
error.message— descrição legívelerror.name— tipo do erro ('SyntaxError', 'TypeError', etc.)error.stack— stack trace completo
O bloco finally
finally roda independente de ocorrer um erro ou não: útil para limpeza.
test('upload de arquivo com limpeza', async ({ page }) => {
const arquivoTemp = await criarArquivoTemp();
try {
await page.setInputFiles('[data-testid="upload"]', arquivoTemp);
await expect(page.locator('[data-testid="upload-success"]')).toBeVisible();
} catch (error) {
console.error('Teste de upload falhou:', error.message);
throw error; // Relança para que o teste ainda falhe
} finally {
await deletarArquivoTemp(arquivoTemp); // Sempre executa, mesmo em falha
}
});finally sempre roda. Valioso para código de limpeza em testes.
async/await e erros
No Playwright, quase tudo é async. Erros em código assíncrono funcionam da mesma forma, você só precisa do await no lugar certo:
// Sem try/catch: rejeição não tratada = teste falha com erro feio
async function getUsuarioDaApi() {
const response = await fetch('/api/user/999');
const data = await response.json();
return data;
}
// Com try/catch: rejeição tratada = você controla a mensagem de erro
async function getUsuarioDaApi() {
try {
const response = await fetch('/api/user/999');
if (!response.ok) {
throw new Error(`Erro da API: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Falha ao buscar usuário:', error.message);
throw error; // Relança se quiser que o chamador trate também
}
}Lançando seus próprios erros
Você pode lançar erros intencionalmente para sinalizar falha:
function validarEmail(email: string): void {
if (!email.includes('@')) {
throw new Error(`Formato de e-mail inválido: "${email}"`);
}
if (email.length > 254) {
throw new Error(`E-mail muito longo: ${email.length} caracteres (máx. 254)`);
}
}
try {
validarEmail('nao-e-email');
} catch (error) {
console.log(error.message); // 'Formato de e-mail inválido: "nao-e-email"'
}Em testes, lançar é como você falha com uma mensagem específica em vez de uma falha genérica de assertion:
async function getTokenAuth(request: APIRequestContext): Promise<string> {
const response = await request.post('/api/auth/login', {
data: { email: 'teste@teste.com', password: 'SenhaValida1' },
});
if (response.status() !== 200) {
throw new Error(`Login falhou: ${response.status()} — não é possível prosseguir com os testes`);
}
const { token } = await response.json();
if (!token) {
throw new Error('Resposta do login sem campo token');
}
return token;
}Tipos de erro
O JavaScript tem vários tipos de erro embutidos:
| Tipo de erro | Quando aparece |
|-------------|---------------|
| Error | Erro genérico (classe base) |
| TypeError | Tipo errado: null.algo, chamar não-função |
| SyntaxError | JavaScript inválido ou parsing de JSON |
| RangeError | Valor fora do range: new Array(-1) |
| ReferenceError | Variável não existe |
Você pode verificar o tipo para tratar erros diferentes de formas diferentes:
try {
await fazerAlgo();
} catch (error) {
if (error instanceof TypeError) {
console.log('TypeError — verifique seus tipos de dados');
} else if (error instanceof SyntaxError) {
console.log('SyntaxError — JSON inválido ou similar');
} else {
throw error; // Erro desconhecido — relança
}
}Padrões comuns em testes Playwright
1. Tentando novamente uma operação após falha
async function aguardarApiPronta(request: APIRequestContext, maxTentativas = 5): Promise<void> {
for (let i = 0; i < maxTentativas; i++) {
try {
const response = await request.get('/api/health');
if (response.status() === 200) return;
} catch (error) {
// API ainda não está pronta, tente novamente
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
throw new Error(`API não ficou pronta após ${maxTentativas} tentativas`);
}2. Coletando erros sem parar a execução
const erros: string[] = [];
for (const email of emailsDeTeste) {
try {
await validarCampoEmail(page, email);
} catch (error) {
erros.push(`${email}: ${error.message}`);
}
}
if (erros.length > 0) {
throw new Error(`Falhas de validação:\n${erros.join('\n')}`);
}3. Classe de erro customizada para código mais limpo
class TestDataError extends Error {
constructor(message: string) {
super(message);
this.name = 'TestDataError';
}
}
// Agora você consegue distinguir erros de setup de dados dos erros de assertion
try {
const usuario = await criarUsuarioTeste(request);
} catch (error) {
if (error instanceof TestDataError) {
console.error('Setup do teste falhou — pulando teste');
test.skip();
}
throw error;
}Erros no Playwright: o que você vai ver
TimeoutError
O erro mais comum no Playwright. Um locator não ficou visível a tempo:
TimeoutError: locator.click: Timeout 30000ms exceeded.
Locator: [data-testid="submit-button"]Esse não é um erro JavaScript que você precisa capturar na maioria dos casos. O Playwright trata e falha o teste com uma mensagem clara. Mas se você quiser tratar um timeout graciosamente (tentar outra coisa se um elemento não aparecer), pode:
try {
await page.locator('[data-testid="popup"]').click({ timeout: 2000 });
} catch (error) {
// Popup não apareceu em 2 segundos — tudo bem
// Continua o teste sem interagir com o popup
}Rejeição de Promise não tratada
Se você chama uma função async sem await e ela lança um erro, pode virar uma "unhandled rejection": não falha o teste imediatamente e a mensagem de erro pode confundir.
// Ruim: sem await, o erro pode ser engolido
page.goto('/admin'); // Se isso falhar, o teste pode passar com estado errado
// Bom: o erro aparece imediatamente
await page.goto('/admin');Sempre use await em operações async nos testes.
Quando NÃO usar try/catch em testes
Não use try/catch para esconder falhas de assertion. Se uma assertion falhar, o teste deve falhar:
// Errado — engole a falha de assertion, teste "passa" quando não deveria
try {
await expect(page.locator('[data-testid="success"]')).toBeVisible();
} catch (error) {
console.log('Elemento não visível, mas continuando...');
}
// Correto — deixa falhas de assertion falharem o teste
await expect(page.locator('[data-testid="success"]')).toBeVisible();try/catch em testes serve para:
- Código de setup e teardown onde a falha não deve mascarar o teste real
- Resiliência intencional (lógica de retry, interações opcionais)
- Criação de dados de teste onde você quer uma mensagem de erro clara e customizada
Não serve para silenciar assertions.
Resumo rápido
try/catchtrata erros: o código emtryroda,catchtrata qualquer erro lançadofinallysempre roda: use para limpeza- Sempre use
awaitem operações async: falhas sem await são difíceis de debugar - Use
throwintencionalmente quando quiser uma mensagem de erro específica - Não capture falhas de assertion: elas devem falhar o teste
instanceofpermite verificar o tipo do erro e tratar erros diferentes de formas diferentes
Tratamento de erros é uma ferramenta para tornar o código mais resiliente e as mensagens de erro mais informativas, não para esconder falhas.
→ Veja também: JavaScript para QA Engineers: O Mínimo para Começar a Automatizar | Async/Await em Português Simples (para Testadores que se Perdem com Promises) | Como Ler Mensagens de Erro do Playwright