Automatizar testes não prova que o mercado quer um produto. Mas ajuda a garantir que, quando alguém decide usá-lo, a experiência funciona como prometido.
Durante muito tempo, pensei nos testes automatizados como uma etapa essencialmente técnica: escrever código, simular ações e verificar se a aplicação responde como deveria.
Essa definição continua correta, mas hoje considero-a incompleta.
Uma aplicação pode funcionar perfeitamente e ainda assim resolver o problema errado. Da mesma forma, uma equipa pode ter identificado um problema real e perder utilizadores porque o fluxo principal falha no browser, num dispositivo móvel ou após uma alteração aparentemente pequena.
Foi por isso que o Playwright me chamou a atenção.
Não apenas por automatizar browsers, mas porque materializa uma ideia que também está no centro do trabalho que fazemos na Painstack:
Não devemos confiar numa suposição quando podemos testá-la.
No desenvolvimento de software, testamos o comportamento da aplicação.
Na construção de um negócio, validamos a existência e a relevância do problema.
São camadas diferentes de evidência. Um teste não substitui o outro.
O que é o Playwright?
O Playwright é uma framework open-source para testes end-to-end de aplicações web.
Um teste end-to-end reproduz um percurso completo pela perspetiva do utilizador. Em vez de verificar apenas uma função isolada, podemos abrir a aplicação, preencher um formulário, clicar num botão e confirmar se o resultado esperado aparece.
Segundo a documentação oficial, o Playwright suporta:
- Chromium;
- Firefox;
- WebKit;
- Windows, Linux e macOS;
- execução local ou em CI;
- modo visual ou headless;
- emulação de diferentes dispositivos móveis.
O Playwright Test também inclui o executor de testes, asserções, isolamento entre testes, paralelização, relatórios e ferramentas de diagnóstico.
Isso permite que a equipa se concentre menos na infraestrutura de automação e mais nos comportamentos que realmente precisa de proteger.
O meu primeiro princípio: testar o percurso, não a implementação
Um dos erros mais comuns na automação é criar testes demasiado ligados à estrutura interna da página.
Imagine um botão com esta implementação:
<button class="button-primary blue large">
Começar validação
</button>
Poderíamos localizá-lo através da sua classe CSS:
await page.locator('.button-primary.blue.large').click();
O problema é que uma alteração visual pode quebrar o teste, mesmo que a experiência continue correta.
O Playwright incentiva localizadores mais próximos da forma como o utilizador e as tecnologias assistivas interpretam a página:
await page
.getByRole('button', { name: 'Começar validação' })
.click();
Neste caso, o teste não está interessado na cor ou no nome interno da classe. Está a verificar se existe um botão identificável com a ação esperada.
Essa distinção é importante.
Um teste útil deve proteger um contrato de experiência, não congelar todos os detalhes da implementação.
Um primeiro teste com Playwright
Num projeto Node.js, podemos iniciar a configuração com:
npm init playwright@latest
Durante a instalação, o Playwright permite escolher TypeScript ou JavaScript, definir a pasta dos testes e instalar os browsers necessários.
Depois disso, podemos criar um teste simples:
import { test, expect } from '@playwright/test';
test('a página principal apresenta a ação de validação', async ({ page }) => {
await page.goto('https://usepainstackai.com/');
await expect(page).toHaveTitle(/Painstack/i);
const validationCta = page
.getByRole('link', { name: /validate/i })
.first();
await expect(validationCta).toBeVisible();
});
O teste abre o site da Painstack e verifica duas condições básicas:
- O título da página identifica o produto;
- A ação principal de validação está visível para o utilizador.
É um exemplo simples, mas representa um comportamento importante.
Se a página carregar sem o seu principal call to action, pode estar tecnicamente online e, ao mesmo tempo, falhar na sua função.
Auto-waiting: esperar por condições, não por segundos
Interfaces modernas nem sempre respondem de forma imediata.
Um elemento pode depender de JavaScript, de uma chamada à API ou de uma animação. Em ferramentas mais antigas, era comum encontrar pausas manuais como esta:
await page.waitForTimeout(3000);
Esse tipo de espera é frágil.
Se a aplicação responder em 500 milissegundos, o teste desperdiça tempo. Se responder em quatro segundos, o teste pode falhar mesmo sem existir um problema funcional.
O Playwright aplica verificações de actionability antes de executar ações. Antes de clicar, por exemplo, confirma condições como visibilidade, estabilidade e capacidade de interação do elemento.
Também oferece asserções assíncronas:
await expect(
page.getByText('Análise concluída')
).toBeVisible();
Em vez de esperar arbitrariamente por três segundos, o teste espera pela condição que realmente interessa.
Isso não elimina automaticamente todos os testes instáveis. Mas reduz a necessidade de sincronização manual e ajuda a escrever verificações mais próximas do comportamento real da interface.
Cada teste começa num ambiente isolado
Outro ponto relevante é o isolamento.
O Playwright utiliza Browser Contexts, comparáveis a perfis novos e independentes do browser. Cada teste pode começar sem cookies, sessões ou estado deixado pelo teste anterior.
Por exemplo:
test('utilizador não autenticado vê a opção de login', async ({ page }) => {
await page.goto('/');
await expect(
page.getByRole('link', { name: /entrar|login/i })
).toBeVisible();
});
Outro teste pode utilizar um estado autenticado próprio, sem depender da execução anterior.
Essa independência tem duas vantagens:
- os testes podem ser executados em paralelo;
- uma falha tende a ser mais fácil de reproduzir.
Quando o teste B só funciona depois do teste A, a suite deixa de representar utilizadores independentes e passa a depender da ordem de execução.
Testar em mais de um browser
Uma aplicação que funciona em Chromium não está automaticamente validada em todos os browsers.
O Playwright permite configurar diferentes projetos no ficheiro playwright.config.ts:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
{
name: 'mobile',
use: { ...devices['iPhone 13'] },
},
],
});
A mesma suite pode então verificar o comportamento em diferentes motores de browser e numa configuração móvel.
O objetivo não deve ser criar uma matriz enorme sem critério. O mais sensato é começar pelos ambientes usados pelo público e pelos percursos com maior impacto.
Cobertura técnica sem prioridade de produto transforma-se facilmente em custo de manutenção.
Quando um teste falha, o Trace Viewer mostra o contexto
Uma mensagem de erro isolada nem sempre explica o que aconteceu.
O Trace Viewer permite analisar a execução passo a passo. Podemos observar o estado da página antes e depois de cada ação e consultar:
- screenshots;
- logs;
- pedidos de rede;
- erros;
- mensagens da consola;
- código-fonte associado à ação;
- snapshots do DOM.
Uma configuração possível é guardar o trace na primeira repetição de um teste:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
trace: 'on-first-retry',
},
});
Isto é particularmente útil em integração contínua. Se um teste falhar fora da máquina do programador, o trace oferece muito mais contexto do que uma mensagem genérica no terminal.
Não substitui uma investigação cuidadosa, mas reduz a quantidade de adivinhação necessária.
O que devemos testar primeiro?
É fácil cair na tentação de automatizar tudo.
Eu prefiro começar por uma pergunta mais concreta:
Que falha impediria o utilizador de obter o valor principal do produto?
Numa aplicação SaaS, a primeira suite pode proteger percursos como:
- A página principal carrega;
- A proposta de valor e a ação principal estão visíveis;
- O utilizador consegue criar uma conta ou entrar;
- O fluxo central aceita os dados necessários;
- O sistema apresenta um estado de progresso compreensível;
- O resultado final pode ser consultado;
- Erros de validação são apresentados de forma clara;
- Os percursos essenciais funcionam em desktop e mobile.
Só depois faz sentido expandir para variações, casos extremos e regressões menos críticas.
Esta priorização aproxima a estratégia de testes da estratégia de produto. Não testamos uma funcionalidade apenas porque existe. Testamo-la porque existe um comportamento importante que não queremos perder.
Playwright não valida se alguém precisa do produto
Esta é a distinção que considero mais importante.
O Playwright consegue confirmar que:
- o botão aparece;
- o formulário aceita dados válidos;
- a navegação chega ao destino esperado;
- o resultado é apresentado;
- o percurso funciona em diferentes browsers.
Mas não consegue provar que:
- o problema é frequente;
- o problema é suficientemente importante;
- o público procura uma alternativa;
- a proposta de valor é compreendida;
- alguém pagaria pela solução.
Essas perguntas exigem outro tipo de evidência: entrevistas, padrões de procura, discussões em comunidades, alternativas existentes, comportamento de utilização e sinais de mercado.
É precisamente nesta camada anterior ao desenvolvimento que a Painstack atua: organizar evidências sobre um problema antes de transformar uma hipótese numa grande aposta de produto.
Podemos resumir assim:
A validação de mercado ajuda-nos a decidir o que vale a pena construir. O Playwright ajuda-nos a verificar se aquilo que construímos continua a funcionar.
Ter apenas uma das duas partes deixa uma lacuna.
Sem validação do problema, corremos o risco de entregar software estável que ninguém precisava.
Sem testes do produto, podemos identificar uma necessidade real e oferecer uma experiência que falha no momento decisivo.
Testes são evidência executável
Gosto de pensar num teste automatizado como uma afirmação executável.
Quando escrevemos:
await expect(validationCta).toBeVisible();
estamos a declarar que a presença dessa ação faz parte do contrato atual do produto.
A cada execução, essa afirmação é novamente verificada contra a aplicação real.
Isso não significa que o teste seja uma verdade permanente. O produto pode mudar, o contrato pode evoluir e o próprio teste pode estar errado. Mas obriga-nos a tornar explícito o comportamento esperado.
O mesmo princípio aplica-se à criação de produtos.
Uma hipótese escrita é melhor do que uma intuição vaga. Uma hipótese confrontada com evidências é melhor do que uma hipótese apenas bem apresentada.
Playwright e Painstack operam em pontos distintos do processo, mas partilham uma disciplina: transformar expectativas implícitas em verificações observáveis.
Conclusão
O Playwright é uma opção relevante para equipas que precisam de testar aplicações web modernas em diferentes browsers, com isolamento, esperas automáticas e ferramentas visuais de diagnóstico.
Mas a sua maior utilidade não está em aumentar artificialmente o número de testes.
Está em proteger os percursos que sustentam a experiência prometida ao utilizador.
Antes de automatizar, precisamos de escolher o comportamento certo.
Antes de construir, precisamos de validar o problema certo.
Nos dois casos, o objetivo não é eliminar totalmente a incerteza. É reduzir decisões baseadas apenas em confiança, opinião ou memória.
Construir rápido continua a ser importante.
Saber o que testar — e o que vale a pena construir — é ainda mais importante.


