Quando um teste Playwright falha, a maioria dos engenheiros rola direto para o número da linha no stack trace e lê a parte errada primeiro. O call log no meio da mensagem de erro é onde está o diagnóstico real. Ele mostra qual condição o Playwright estava verificando e o que observou: se o elemento estava ausente, oculto, desabilitado ou coberto por um overlay.

A anatomia de um erro do Playwright

Error: locator.click: Timeout 30000ms exceeded.
Call log:
  - waiting for getByRole('button', { name: 'Submit' })

    waiting for element to be visible, enabled and stable
    element is not visible - waiting...
    element is not visible - waiting...
    element is not visible - waiting...

  at Object.<anonymous> (tests/checkout.spec.ts:45:40)

Três partes:

1. Tipo do erro e mensagem: locator.click: Timeout 30000ms exceeded — qual ação falhou e o que estourou o timeout

2. Call log: o que o Playwright estava fazendo e observando enquanto aguardava

3. Stack trace: onde no código do teste aconteceu

Leia nessa ordem: tipo do erro primeiro, call log segundo, stack trace terceiro. O call log é o que mais informa.

Erros comuns e o que significam

Timeout exceeded

Error: locator.click: Timeout 30000ms exceeded.

O Playwright não conseguiu completar a ação dentro do timeout. O call log explica por quê. Causas comuns:

  • O elemento não existe no DOM
  • O elemento existe mas está oculto (display: none, visibility: hidden, opacity: 0)
  • O elemento existe e está visível, mas está desabilitado
  • O elemento está coberto por outro elemento (overlay, modal, toast notification)
  • A navegação da página não terminou antes da próxima ação
Como resolver: leia o call log. Ele lista qual condição não foi atendida (element is not visible, element is not stable, element is disabled). Esse é o problema real.

Strict mode violation

Error: strict mode violation: getByRole('button', { name: 'OK' }) resolved to 2 elements

O locator encontrou mais de um elemento. O Playwright exige que locators sejam únicos, a menos que você especifique o contrário.

Como resolver: seja mais específico. Adicione um filtro de contexto:

// Muito genérico
page.getByRole('button', { name: 'OK' })

// Mais específico — restrito ao modal
page.getByRole('dialog').getByRole('button', { name: 'OK' })

// Ou use nth se a ordem for estável
page.getByRole('button', { name: 'OK' }).first()

Locator not found

Error: locator.fill: Error: strict mode violation: getByLabel('Email') resolved to 0 elements

Nenhum elemento correspondeu. O locator está errado, o elemento ainda não está na página, ou você está na página errada.

Como resolver: verifique o locator. Abra o teste com a flag --debug para inspecionar o estado da página:

npx playwright test --debug tests/login.spec.ts

Error: page.goto: Timeout 30000ms exceeded.
call log:
  navigating to "http://localhost:3000/login", waiting until "load"

A página não terminou de carregar. Possíveis causas:

  • O servidor está lento ou não está rodando
  • A opção waitUntil está muito restritiva ('networkidle' em páginas com polling em background)
  • Um recurso (imagem, script) está travando o evento de load
Como resolver: verifique se o servidor está rodando. Tente waitUntil: 'domcontentloaded' se não precisar aguardar todos os recursos. Use a aba Network no Trace Viewer para ver o que está travando.

Expect timeout

Error: expect(locator).toHaveText() with timeout 5000ms
Received string: ""
Expected string: "Order confirmed"

A assertion não passou dentro do timeout. O elemento existe mas tem o conteúdo errado, ou o conteúdo ainda não carregou.

Como resolver: o conteúdo realmente está carregando? Aumente o timeout temporariamente para descartar problema de timing: await expect(el).toHaveText('Order confirmed', { timeout: 15000 }). Se passar com mais tempo, é um problema de performance, não de selector.

Execution context destroyed

Error: Execution context was destroyed, most likely because of a navigation.

O Playwright estava segurando uma referência a um elemento da página quando a página navegou para outro lugar. Causa comum: você fez const text = page.getByText('foo') e depois navegou antes de avaliar o locator.

Como resolver: avalie os locators antes de navegar:

// Quebrado — locator avaliado depois da navegação
const text = page.getByText('Confirmation');
await page.getByRole('button', { name: 'Submit' }).click(); // dispara navegação
await expect(text).toBeVisible(); // a página não existe mais

// Correto — faça assertion antes da navegação, ou consulte o locator novamente depois
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page).toHaveURL('/confirmation');
await expect(page.getByText('Order confirmed')).toBeVisible();

Target closed

Error: Target page, context or browser has been closed

O contexto do navegador foi fechado antes do teste terminar. Acontece quando:

  • Um teste fecha o contexto manualmente no lugar errado
  • Um bloco beforeAll fechou um contexto que afterAll ou outros testes ainda precisavam
  • Um teste travou e o código de limpeza rodou enquanto outras coisas ainda estavam em execução

Erros de rede

Error: net::ERR_CONNECTION_REFUSED at http://localhost:3000

O servidor não está rodando. Verifique:

  • O servidor de dev foi iniciado antes dos testes?
  • A baseURL está correta?
  • A porta está correta?

No CI, adicione um step para iniciar o servidor antes do Playwright rodar, ou use webServer no config:

// playwright.config.ts
webServer: {
  command: 'npm run start',
  url: 'http://localhost:3000',
  reuseExistingServer: !process.env.CI,
},

Fluxo de debugging

Passo 1: leia o tipo do erro e o call log. O call log mostra o que o Playwright estava aguardando e o que observou. Passo 2: abra o Trace Viewer. npx playwright show-trace test-results/.../trace.zip: o snapshot do DOM mostra exatamente o que estava na página quando a falha aconteceu. Passo 3: rode em modo debug (--debug) para avançar pelo teste passo a passo de forma interativa. Passo 4: use page.pause() para congelar o teste em um ponto específico e inspecionar manualmente.

await page.goto('/checkout');
await page.pause(); // O teste congela aqui e abre o Inspector
await page.getByRole('button', { name: 'Pay' }).click();

O Inspector abre um navegador com a toolbar do Playwright: você interage com a página, roda queries de locator e acompanha as ações em tempo real.

→ Veja também: Playwright Trace Viewer: Depure Testes com Falha Como um Profissional | Depurando Testes Instáveis: Um Guia Prático | Assertions no Playwright: O Guia Completo