O nosso interesse, declarado: somos a Geonode e vendemos proxies, e as capturas de ecrã através de um proxy são um dos casos de utilização mais «limpos» do nosso produto — verificar como uma página se apresenta realmente a partir de outro país é algo que nenhuma API nos diz. A ressalva a ter em conta é o custo: um navegador descarrega todas as imagens, tipos de letra, scripts e vídeos em pré-carregamento, pelo que a captura de ecrã é a atividade que mais largura de banda consome quando se tem tráfego medido. Há uma secção abaixo sobre como reduzir isso, e a técnica aí descrita irá poupar-lhe mais dinheiro do que escolher um fornecedor mais barato.
Os três tipos de captura de ecrã
Viewport — o que está visível no momento, a opção predefinida:
await page.screenshot({ path: 'viewport.png' });
Página completa — a documentação descreve-a como «uma captura de ecrã de uma página completa com rolagem, como se tivesse um ecrã muito alto e a página coubesse nele na totalidade»:
await page.screenshot({ path: 'full.png', fullPage: true });
Elemento — «Por vezes, é útil tirar uma captura de ecrã de um único elemento»:
await page.getByRole('article').screenshot({ path: 'element.png' });
A escolha entre elas depende principalmente do que pretende fazer com o resultado. As capturas de ecrã da janela de visualização respondem à pergunta «o que é que o utilizador vê primeiro». As capturas de ecrã de página inteira respondem à pergunta «o que está nesta página». As capturas de ecrã de elementos respondem à pergunta «este componente está correto?», e são as mais estáveis das três para comparação, porque excluem tudo aquilo sobre o qual não perguntou.
Capturas de ecrã de página inteira e onde podem falhar
fullPage: true é a opção mais utilizada e aquela que apresenta mais ressalvas.
O conteúdo carregado de forma diferida pode não estar presente. O Playwright faz a rolagem para capturar, mas as imagens e os componentes que são carregados à medida que o cursor passa por eles podem não ter terminado de carregar quando a captura estiver concluída. A solução fiável consiste em percorrer a página deliberadamente e aguardar pelo conteúdo esperado:
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await expect(page.getByRole('img').last()).toBeVisible();
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({ path: 'full.png', fullPage: true });
Os cabeçalhos fixos repetem-se ou flutuam de forma estranha. Os elementos com position: fixed ou sticky comportam-se de forma imprevisível numa captura unida. A opção style — uma «cadeia CSS a inserir na página para aplicar estilo durante a captura» — é a solução mais simples:
await page.screenshot({
path: 'full.png',
fullPage: true,
style: '.sticky-header { position: absolute !important; }',
});
Páginas muito longas produzem ficheiros muito grandes. Um feed com deslocamento infinito não tem um fim natural. Considere utilizar clip para capturar uma região definida, o que requer «um objeto que especifique o recorte da imagem resultante».
As sobreposições também são capturadas. Banners de cookies, widgets de chat e janelas modais aparecem na captura de ecrã exatamente como aparecem ao utilizador. Se não os quiser, feche-os primeiro — e, se não for possível, a ferramenta mask é a solução.
Capturas de ecrã e buffers de elementos
As capturas de ecrã de elementos deslocam o elemento para o campo de visão e capturam apenas a sua caixa delimitadora, o que as torna a opção predefinida adequada para verificações ao nível dos componentes.
const card = page.getByTestId('product-card').first();
await card.screenshot({ path: 'card.png' });
Há duas coisas que não fazem: capturar conteúdo recortado por overflow: hidden
e capturar qualquer elemento fora da caixa do elemento, mesmo que este se sobreponha visualmente.
Buffers em vez de ficheiros. A documentação refere que «em vez de gravar num ficheiro, pode obter um buffer com a imagem e processá-lo posteriormente ou enviá-lo para um serviço de comparação de píxeis de terceiros». Omita path
e receberá os bytes de volta:
const buffer = await page.screenshot();
const base64 = buffer.toString('base64');
Este é o formato que deve utilizar sempre que a captura de ecrã for enviada para outro local que não o disco local — um armazenamento de objetos, uma API, um relatório ou um serviço de comparação. Além disso, evita completamente o sistema de ficheiros, o que é importante em executores em contentores, onde o disco é efémero.
As opções que tornam as capturas de ecrã reproduzíveis
Se estiver a comparar capturas de ecrã entre si, estas opções não são opcionais. Se estiver apenas a dar uma vista de olhos a uma delas, ignore-as.
| Opção | Valores | O que faz |
|---|---|---|
animations |
| disabled
, allow
| «Quando definido como “desativado”, interrompe as animações CSS durante a captura» |
| caret
| hide
, initial
| «Quando definido como “ocultar”, oculta o cursor de texto durante a captura de ecrã» |
| mask
| Locator[]
| «Especifica os localizadores que devem ser mascarados ao realizar a captura de ecrã» |
| maskColor
| cor CSS, predefinição #F0F
| «Especifica a cor a utilizar nas regiões mascaradas» |
| scale
| css
, device
| «A escala de renderização da página web» |
| omitBackground
| booleano, predefinição false
| «Oculta o fundo branco predefinido e permite capturar capturas de ecrã transparentes» |
| type
| png
, jpeg
, valor predefinido png
| «Especifica o formato do ficheiro da captura de ecrã» |
| quality
| 0–100 | «A qualidade da imagem para o formato JPEG» — apenas JPEG |
| style
| cadeia CSS | Injetada na página durante o período de captura |
Os quatro que resolvem a maioria dos problemas de reprodutibilidade:
**animations: 'disabled'
** elimina a maior fonte de diferença entre duas capturas da mesma página. Qualquer transição CSS em curso produz um resultado em pixels diferente a cada execução.
**mask
** substitui regiões por uma cor sólida, o que permite excluir conteúdo genuinamente variável — carimbos de data/hora, identificadores de sessão, recomendações personalizadas, anúncios — sem abandonar totalmente a comparação:
await page.screenshot({
path: 'page.png',
mask: [page.getByTestId('timestamp'), page.locator('.ad-slot')],
maskColor: '#000000',
});
**scale: 'css'
** captura com dimensões em píxeis CSS em vez da proporção de píxeis do dispositivo, para que um computador com DPI elevado e um executor de CI produzam imagens de tamanhos comparáveis. Defina-o explicitamente em vez de confiar no valor predefinido, uma vez que esta é a opção mais suscetível de diferir entre o seu portátil e o servidor de compilação.
**caret: 'hide'
** remove o cursor de texto intermitente, que, de outra forma, aparece em cerca de metade das suas capturas de qualquer página com um campo de entrada em foco.
Há mais três aspetos a definir para garantir a reprodutibilidade, nenhum dos quais diz respeito às opções de captura de ecrã: fixe o tamanho da janela de visualização na sua configuração, fixe a localização e o fuso horário e fixe os tipos de letra — a disponibilidade de tipos de letra difere entre o computador de um programador e um contentor, e tipos de letra diferentes significam um layout diferente.
Capturas de ecrã automáticas em caso de falha no teste
Esta é a configuração de captura de ecrã mais útil no Playwright e requer apenas uma linha:
export default defineConfig({
use: {
screenshot: 'only-on-failure',
trace: 'retain-on-failure',
video: 'retain-on-failure',
},
});
screenshot: 'only-on-failure'
captura a página no momento em que um teste falha e anexa-a ao relatório. As opções disponíveis são off
, on
e only-on-failure
; on
captura em todos os testes e produz muitos artefactos.
Combinar isto com trace
é a parte em que vale a pena insistir, porque um rastreio inclui instantâneos do DOM, atividade de rede e todas as ações com os respetivos tempos. Uma captura de ecrã mostra que a página estava errada; um rastreio explica porquê. Para qualquer coisa que seja executada de forma automática, ambas as opções devem estar ativadas.
Esta configuração é também a forma mais rápida de diagnosticar a categoria confusa de falhas em que uma página foi renderizada — mas não a página que se esperava. Uma página de desafio, um redirecionamento de início de sessão ou uma variante regional produzem todos tempos de espera que parecem problemas de elementos até se ver a captura de ecrã.
Comparação visual com o toHaveScreenshot
Para testes de regressão visual efetivos, em vez de capturas ad hoc:
await expect(page).toHaveScreenshot('homepage.png');
await expect(page.getByRole('navigation')).toHaveScreenshot('nav.png');
Na primeira execução, o programa cria uma linha de base; nas execuções seguintes, compara e reporta falhas caso haja diferenças. Atualize as linhas de base deliberadamente com --update-snapshots
.
Três notas práticas.
As linhas de referência são específicas de cada plataforma. A renderização das fontes difere entre sistemas operativos, pelo que uma linha de referência gerada no macOS não corresponderá a uma gerada num contentor Linux. Gere linhas de referência no mesmo ambiente em que os seus testes são executados — normalmente em CI, geralmente através de um contentor que também pode executar localmente.
Defina uma tolerância. A correspondência exata de píxeis produz falhas devido a diferenças de antialiasing que nenhum ser humano notaria. Definir «maxDiffPixels
» ou «maxDiffPixelRatio
» na sua configuração é o que torna o conjunto de testes utilizável.
Mascarar todas as variáveis antes de começar. Um teste visual que falha sempre que um carimbo de data/hora muda será desativado no espaço de uma semana, o que é pior do que não o ter.
Capturas de ecrã através de um proxy
Este é um caso em que estamos realmente no nosso elemento, e é um bom exemplo.
Configure o proxy na sua configuração do Playwright:
const context = await browser.newContext({
proxy: { server: 'http://proxy.example.com:9000', username: 'u', password: 'p' },
locale: 'de-DE',
timezoneId: 'Europe/Berlin',
});
Repare nos endereços locale
e timezoneId
juntamente com o proxy. Um endereço de saída alemão com a localização en-US
e o fuso horário de Londres é uma combinação que nenhum visitante real utiliza, e muitos sites utilizam a localização independentemente do endereço para decidir o que apresentar. Defina os três em conjunto, caso contrário estará a testar algo diferente do que pretendia.
O que isto realmente responde: o que um visitante real nesse país vê. Preços regionais, exibição da moeda, disponibilidade, banners promocionais, se a sua publicidade está a ser exibida onde pagou para que fosse e o que aparece juntamente com o seu conteúdo. Nenhuma API lhe fornece isto, porque a resposta é uma página renderizada.
Quanto custa e como reduzir os custos. Um navegador carrega tudo. Em tráfego residencial com limite de dados — o nosso começa nos 0,79 $/GB, verificado em setembro de 2026 na nossa página de preços — uma captura de ecrã em vinte mercados acumula custos rapidamente. Bloquear os tipos de recursos de que não precisa é a medida mais eficaz:
await page.route('**/*.{woff,woff2,mp4,webm}', route => route.abort());
Repare no que não consta dessa lista. Se a captura de ecrã for o produto final, não pode bloquear imagens — isso iria contra o objetivo. Bloqueie tipos de letra e multimédia, mantenha as imagens e aceite que a verificação visual é, por natureza, o tipo de trabalho de proxy mais dispendioso. Nos casos em que apenas precise de confirmar o conteúdo do texto, em vez da aparência, bloqueie também as imagens e dispense completamente a captura de ecrã.
E verifique se a geolocalização foi efetivamente aplicada. Faça a captura de ecrã e analise-a. Se uma página capturada através de uma saída brasileira mostrar os mesmos preços que a sua, a segmentação não está a funcionar, independentemente do que uma pesquisa de IP indicar. Esta é exatamente a falha silenciosa que descrevemos em por que é importante testar proxies — e as capturas de ecrã são excepcionalmente eficazes a detetá-la, porque um ser humano consegue percebê-la num só olhar.
Capturas de ecrã em grande escala
Quando se começa a tirar mais do que algumas, há algumas práticas que evitam que a tarefa se torne incontrolável.
Reutilize o navegador, não o contexto. Iniciar um navegador é dispendioso; criar um contexto é barato. Para uma execução que abranja muitas páginas ou muitas regiões, inicie o navegador uma única vez e crie um contexto novo por unidade de trabalho — isso permite-lhe ter cookies e armazenamento isolados sem ter de pagar repetidamente o custo de inicialização:
const browser = await chromium.launch();
for (const country of countries) {
const ctx = await browser.newContext({ proxy: { server: proxyFor(country) } });
const page = await ctx.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: `shots/${country}.png`, fullPage: true });
await ctx.close();
}
await browser.close();
Não utilize networkidle como condição de espera. As páginas com beacons de análise, websockets ou polling nunca ficam inativas, e a espera expira. Aguarde pelo elemento que indica que a página está pronta:
await page.goto(url);
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
await page.screenshot({ path: 'shot.png' });
Limite deliberadamente a concorrência. Cada contexto do navegador consome memória real — algumas centenas de megabytes é normal assim que uma página é carregada. Executar trinta em paralelo num executor pequeno produz falhas que parecem tempos de espera esgotados, mas que, na realidade, se devem à falta de espaço na máquina. Comece com quatro ou cinco e aumente gradualmente, mantendo-se atento à memória.
Nomeie os ficheiros de forma a poder encontrá-los. Um diretório com nomes como screenshot-1.png até screenshot-400.png é inutilizável. Inclua o destino, a região e um carimbo de data/hora no nome do ficheiro e guarde o URL juntamente com a imagem.
Comprima antes de arquivar. O formato PNG não tem perdas, mas ocupa muito espaço. Se as imagens se destinam à revisão humana e não à comparação de píxeis, o formato JPEG disponível em quality: 80 tem normalmente uma fração do tamanho e é visualmente indistinguível — e, para uma execução em vinte mercados dentro de um prazo, essa diferença traduz-se na fatura de armazenamento.
Lide com falhas sem interromper a execução. Uma página que não carregue não deve fazer com que as outras dezanove sejam abandonadas. Conclua cada captura, registe o erro e continue — depois, indique quais os alvos que falharam, em vez de descobrir que todo o trabalho falhou no terceiro alvo.
Quando uma captura de ecrã não é a ferramenta adequada
Quando o que se quer são os dados. Se precisares do preço, extrai o preço. Uma captura de ecrã de um número é um número que depois tens de ler a partir de uma imagem. As capturas de ecrã servem para mostrar a aparência; os seletores servem para o conteúdo.
Quando se quer saber por que razão um teste falhou. Um registo de execução é, sem dúvida, mais informativo e inclui, de qualquer forma, a captura de ecrã.
Quando a página é enorme. As capturas de ecrã de páginas inteiras com deslocamento infinito produzem ficheiros enormes que ninguém vai abrir. Recorte apenas a região que interessa.
Quando se está a verificar texto. Verifique o texto. O comando «expect(locator).toHaveText()» fornece uma mensagem de falha legível; uma comparação de pixels dá-lhe apenas uma imagem da mesma.
Quando precisar de arquivar em grande escala. As capturas de ecrã são grandes e, quando se trata de milhares delas em vários mercados, ocupam muito espaço de armazenamento e largura de banda. Armazene hashes ou comparações e guarde as imagens completas apenas quando algo tiver mudado.
Perguntas frequentes
Como faço uma captura de ecrã no Playwright?
await page.screenshot({ path: 'shot.png' }) para a janela de visualização, { fullPage: true } para toda a página rolável e locator.screenshot() para um único elemento. Omita path para obter um buffer em vez de gravar num ficheiro.
Como faço uma captura de ecrã de página inteira?
Passe fullPage: true. Tenha em atenção que o conteúdo carregado de forma diferida pode ainda não ter chegado e que os elementos fixos ou «sticky» podem comportar-se de forma estranha no resultado final — faça primeiro uma deslocamento deliberado e utilize a opção style para neutralizar o posicionamento fixo durante a captura.
Como faço uma captura de ecrã de um único elemento?
Chame screenshot() num localizador em vez de na página: await page.getByTestId('card').screenshot({ path: 'card.png' }). O Playwright desloca o elemento para a área visível e captura a sua caixa delimitadora. O conteúdo recortado por overflow: hidden não é incluído.
Como posso garantir que as capturas de ecrã do Playwright sejam consistentes entre execuções?
Defina animations: 'disabled' e caret: 'hide', mascare regiões variáveis com mask e defina explicitamente scale. Em seguida, fixe o tamanho da janela de visualização, a localização, o fuso horário e os tipos de letra disponíveis, uma vez que todos estes quatro fatores afetam o layout e nenhum deles constitui uma opção de captura de ecrã.
Como posso capturar uma captura de ecrã automaticamente quando um teste falha?
Defina screenshot: 'only-on-failure' no bloco use da sua configuração do Playwright. Combine-o com trace: 'retain-on-failure' — um rastreio inclui instantâneos do DOM, atividade de rede e tempos de ação, o que explica a falha em vez de apenas a mostrar.
Posso obter uma captura de ecrã como base64 em vez de um ficheiro?
Sim. Omita a opção path e screenshot() devolve um buffer, que pode converter com buffer.toString('base64'). A documentação sugere isto para pós-processamento ou para enviar para um serviço de comparação de pixels, e evita o sistema de ficheiros em executores de CI efémeros.
Como oculto conteúdo dinâmico de uma captura de ecrã?
Utilize a opção mask com um conjunto de localizadores, o que substitui essas regiões por uma cor sólida — maskColor tem como valor predefinido #F0F e pode ser alterado. É assim que se mantém a comparação visual útil em páginas que contêm registos de data e hora, dados de sessão ou publicidade.
Posso tirar capturas de ecrã através de um proxy para ver páginas regionais?
Sim, e essa é uma das melhores formas de o utilizar. Defina o proxy no contexto do navegador e configure locale e timezoneId de forma a corresponderem ao país — muitos sites utilizam a localização independentemente do endereço. Em seguida, analise a imagem resultante para confirmar que o conteúdo regional difere efetivamente, em vez de confiar numa pesquisa de IP.
Conclusão
Fazer uma captura de ecrã no Playwright resume-se a uma linha de código. Fazer uma que tenha algum significado requer um pouco mais de trabalho.
Se a captura de ecrã se destinar a ser vista por uma pessoa de uma só vez — um artefacto de falha, um relatório de bug, uma verificação de como uma página aparece no Brasil —, as predefinições são suficientes e screenshot: 'only-on-failure' na vossa configuração é a linha mais valiosa que podem adicionar. Combinem-na com um trace, porque um trace explica o que uma captura de ecrã apenas mostra.
Se a captura de ecrã for comparada com outra captura de ecrã, tudo muda. Desative as animações, oculte o cursor, mascare as regiões variáveis, fixe a escala e defina a janela de visualização, a localização, o fuso horário e os tipos de letra. Em seguida, gere linhas de base no mesmo ambiente em que os testes são executados, porque a renderização dos tipos de letra difere entre plataformas e uma linha de base do seu portátil nunca corresponderá a um contentor.
E para a verificação geográfica — que é onde uma página renderizada supera genuinamente os dados estruturados — define o proxy, a localização e o fuso horário em conjunto e, em seguida, analisa a imagem para confirmar que a segmentação funcionou. A largura de banda representa o custo, as imagens são o único tipo de recurso que não podes bloquear e é simplesmente isso que a verificação visual custa.
