Playwright além do básico

TL;DR

O Playwright vai muito além do E2E clássico. Autenticação reusável: faça login uma vez, salve o storageState (cookies + localStorage) e reuse em todos os testes — sem logar em cada um. Interceptar rede: page.route() mocka respostas HTTP direto no browser (ou reuse os handlers do MSW). Testes visuais: toHaveScreenshot() compara a tela pixel a pixel para pegar regressões visuais. E o component testing (experimental) roda componentes React em browser real (Chromium/Firefox/WebKit) em vez de jsdom — eliminando o “passa no jsdom, quebra no browser”. São as capacidades que fazem o Playwright cobrir do componente ao fluxo completo.

O problema: E2E básico é lento e repetitivo

Você tem os E2E dos caminhos críticos (nota 13). Mas logo bate em fricções: todo teste precisa de um usuário logado — e logar via UI em cada um é lento e repetitivo. Alguns testes precisam de uma resposta de API específica (um erro 500, um estado raro) que é difícil de reproduzir no backend real. E há bugs visuais (um CSS que quebrou o layout) que nenhuma asserção de texto pega. Além disso, o teste de componente em jsdom (nota 08) às vezes mente — passa no jsdom mas quebra no browser real, porque jsdom não é um browser de verdade.

O Playwright tem resposta para cada uma dessas fricções. São os recursos que o transformam de “runner de E2E” em plataforma de teste de browser completa.

Autenticação reusável: storageState

Logar via UI em cada teste é o maior desperdício de tempo em suítes E2E. A solução: logar uma vez, salvar o estado de autenticação (cookies + localStorage) num arquivo, e reusá-lo:

// auth.setup.ts — roda uma vez antes dos testes
import { test as setup } from '@playwright/test';
 
setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('E-mail').fill('ana@ex.com');
  await page.getByLabel('Senha').fill('senha');
  await page.getByRole('button', { name: 'Entrar' }).click();
  await page.context().storageState({ path: 'auth.json' }); // salva o estado
});
 
// playwright.config.ts — os testes começam já logados
export default defineConfig({
  projects: [
    { name: 'setup', testMatch: /auth\.setup\.ts/ },
    { name: 'chromium', use: { storageState: 'auth.json' }, dependencies: ['setup'] },
  ],
});

Todos os testes do projeto chromium começam já autenticados, sem repetir o login. É mais rápido e isola o “fluxo de login” no seu próprio teste (onde ele realmente deve ser testado).

Interceptar a rede: page.route

Assim como o MSW (nota 09), o Playwright pode mockar respostas HTTP — útil para forçar estados difíceis de reproduzir (erro do servidor, resposta lenta, dado específico):

await page.route('**/api/pedidos', (route) =>
  route.fulfill({ status: 500, body: 'erro' })
);
await page.goto('/pedidos');
await expect(page.getByText('Falha ao carregar')).toBeVisible();

graph TB
    A[Playwright além do E2E] --> B["storageState<br/>login 1x, reusa"]
    A --> C["page.route<br/>mockar rede no browser"]
    A --> D["toHaveScreenshot<br/>regressão visual"]
    A --> E["component testing<br/>browser real, não jsdom"]
    style B fill:#4A90D9,color:#fff
    style C fill:#4A90D9,color:#fff
    style D fill:#4A90D9,color:#fff
    style E fill:#4A90D9,color:#fff

Testes visuais: toHaveScreenshot

Bugs de layout (um CSS que empurrou tudo, um componente que sumiu) não têm texto para asserir. O visual regression testing compara um screenshot atual com um de referência:

await expect(page).toHaveScreenshot('home.png'); // 1ª vez grava; depois compara

Na primeira execução grava a imagem de referência; nas seguintes compara pixel a pixel (com tolerância configurável) e falha se divergir. É o análogo visual do snapshot (nota 11) — e tem os mesmos cuidados: fontes/animações/dados dinâmicos causam diferenças espúrias, então estabilize (desligue animações, use dados fixos) antes de capturar.

Component testing em browser real

O teste de componente com Testing Library roda em jsdom — uma simulação de DOM, não um browser. Isso gera o problema “passa no jsdom, quebra no Safari”: jsdom não implementa layout real, algumas APIs, comportamentos de CSS. O component testing do Playwright (ainda experimental em 2026) roda o componente num browser de verdade (Chromium/Firefox/WebKit):

import { test, expect } from '@playwright/experimental-ct-react';
import { Botao } from './Botao';
 
test('renderiza e clica', async ({ mount }) => {
  const comp = await mount(<Botao>Enviar</Botao>);
  await expect(comp).toContainText('Enviar');
});

Para UIs complexas (drag-and-drop, WebGL, media, medições de layout), isso elimina a divergência jsdom-vs-browser. Como ainda é experimental, para componentes simples o combo Vitest + Testing Library (jsdom) segue mais rápido e maduro; o CT do Playwright brilha onde o browser real importa.

Screenshots visuais sem estabilizar o ambiente

O que acontece: o teste visual falha em toda execução com diferenças mínimas — uma fonte que renderiza diferente, um cursor piscando, um timestamp na tela. Por quê: comparação pixel a pixel é sensível a qualquer não-determinismo: animações, fontes do SO, dados dinâmicos, antialiasing entre ambientes (seu Mac vs. o Linux da CI). Como evitar: estabilize antes de capturar — desligue animações (animations: 'disabled'), fixe dados/datas, rode a captura de referência no mesmo ambiente da CI (via Docker), e use maxDiffPixels/tolerância. Screenshot instável é o snapshot gigante da nota 11 em forma visual.

Playwright além do básico em uma frase: storageState reusa o login (rápido), page.route mocka a rede no browser para estados difíceis, toHaveScreenshot pega regressões visuais, e o component testing experimental roda componentes em browser real — cobrindo do componente ao fluxo, com os mesmos cuidados de estabilização dos snapshots.

Em entrevista

“Playwright goes well beyond basic E2E. For auth I log in once, save the storageState — cookies and localStorage — and reuse it, so tests don’t each log in through the UI. page.route lets me mock network responses in the browser to force hard-to-reproduce states like a 500. toHaveScreenshot does visual regression testing, comparing pixels to catch layout bugs. And its experimental component testing runs components in a real browser instead of jsdom, killing the ‘works in jsdom, breaks in Safari’ problem — valuable for complex UIs, though for simple components Vitest plus Testing Library is still faster and more mature.”

PTEN
Estado de autenticaçãoAuth state / storageState
Interceptar a redeIntercept the network
Regressão visualVisual regression
Component testing em browser realReal-browser component testing
Estabilizar o ambienteStabilize the environment
Tolerância de diferençaDiff tolerance

O que vem a seguir

Você conhece o Playwright a fundo. Mas por que ele, e não o Cypress, que dominou a categoria antes? Entender essa disputa — e os trade-offs de arquitetura — é o que fecha uma decisão de ferramenta bem fundamentada.

Fontes