A comparação de screenshots pixel a pixel falha no momento em que a renderização de fonte varia entre versões do sistema operacional. Também quebra quando uma animação é capturada no meio do frame, ou um timestamp muda. Ferramentas de testes visuais com IA como Percy e Applitools substituem diffs de pixels por comparação semântica, distinguindo uma regressão real de layout do ruído de renderização.
O problema com a comparação pixel a pixel
// Comparação de screenshot tradicional
test('homepage parece correta', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png'); // Falha em diferenças de 1px
});Isso quebra para:
- Diferenças de renderização de fonte entre versões de OS e navegador
- Animações capturadas em frames diferentes
- Conteúdo dinâmico (timestamps, nomes de usuário, anúncios)
- Variações de antialiasing
- Diferenças de posição de scroll
Você acaba com uma escolha: falhas constantes por falsos positivos, ou limiares relaxados que deixam bugs visuais reais passarem.
Como o teste visual com IA funciona
Serviços de teste visual com IA usam visão computacional e machine learning para:
1. Entender o layout — sabe que um botão é um botão, não apenas pixels
2. Ignorar diferenças irrelevantes — variações de renderização de texto, diferenças menores de espaçamento
3. Sinalizar mudanças significativas — shifts de layout, elementos faltando, mudanças de cor, conteúdo sobreposto
4. Agrupar falhas similares — 50 testes mostrando o mesmo bug viram um problema agrupado
A IA é treinada em milhares de mudanças reais de UI, aprendendo quais diferenças são bugs versus ruído de renderização.
Percy (BrowserStack)
Percy é a ferramenta de teste visual com IA mais estabelecida, adquirida pelo BrowserStack.
Setup com Playwright
npm install --save-dev @percy/cli @percy/playwright// tests/visual.spec.ts
import { test } from '@playwright/test';
import percySnapshot from '@percy/playwright';
test('visual da homepage', async ({ page }) => {
await page.goto('/');
await percySnapshot(page, 'Homepage');
});
test('visual da página de login', async ({ page }) => {
await page.goto('/login');
await percySnapshot(page, 'Página de Login');
});
test('dashboard após login', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', 'user@test.com');
await page.fill('[data-testid="password"]', 'ValidPass1');
await page.click('[data-testid="submit"]');
await page.waitForURL('/dashboard');
await percySnapshot(page, 'Dashboard - Autenticado');
});Rodando Percy
# Defina seu token Percy (de app.percy.io)
PERCY_TOKEN=seu_token npx percy exec -- npx playwright testNa primeira execução, o Percy tira screenshots de baseline. Execuções subsequentes comparam com o baseline, e a IA do Percy sinaliza mudanças visuais reais para revisão humana.
Integração com CI
# .github/workflows/visual-tests.yml
- name: Rodar testes visuais Percy
run: npx percy exec -- npx playwright test tests/visual.spec.ts
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}O Percy posta os resultados como uma verificação no PR: os diffs visuais aparecem diretamente no seu pull request do GitHub.
Applitools Eyes
O Applitools usa seu motor "Visual AI", que afirma ser mais preciso do que a comparação de pixels. Suporta testes responsivos e comparação no nível de componente.
npm install --save-dev @applitools/eyes-playwrightimport { test } from '@playwright/test';
import { Eyes, Target, Configuration } from '@applitools/eyes-playwright';
test('regressão visual', async ({ page }) => {
const eyes = new Eyes();
const configuration = new Configuration();
configuration.setApiKey(process.env.APPLITOOLS_API_KEY!);
eyes.setConfiguration(configuration);
await eyes.open(page, 'Meu App', 'Teste da Homepage');
await page.goto('/');
await eyes.check('Homepage', Target.window().fully());
await page.goto('/products');
await eyes.check('Página de Produtos', Target.window().fully());
await eyes.close();
});O Ultrafast Grid
O principal recurso do Applitools: o Ultrafast Grid renderiza seu snapshot do DOM em múltiplos navegadores e viewports simultaneamente sem realmente rodar navegadores na sua máquina:
import { VisualGridRunner, BrowserType, DeviceName, ScreenOrientation } from '@applitools/eyes-playwright';
const runner = new VisualGridRunner({ testConcurrency: 5 });
const configuration = new Configuration();
configuration.addBrowser(1280, 800, BrowserType.CHROME);
configuration.addBrowser(1440, 900, BrowserType.FIREFOX);
configuration.addDeviceEmulation(DeviceName.iPhone_12, ScreenOrientation.PORTRAIT);
configuration.addDeviceEmulation(DeviceName.iPad_Pro, ScreenOrientation.LANDSCAPE);Uma execução de teste do Playwright, resultados visuais para 4 configurações de navegador/dispositivo.
Comparação de screenshot integrada do Playwright
O Playwright tem comparação visual básica integrada, sem IA:
// Integrado - comparação de pixels com limiar configurável
test('screenshot da homepage', async ({ page }) => {
await page.goto('/');
// Permite até 1% de diferença de pixels
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixelRatio: 0.01,
});
// Ou definir contagem absoluta de pixels
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixels: 50,
});
});// Mascarar conteúdo dinâmico
await expect(page).toHaveScreenshot('homepage.png', {
mask: [
page.getByTestId('timestamp'),
page.getByTestId('user-avatar'),
page.getByTestId('ad-banner'),
],
});Lidando com conteúdo dinâmico
O principal desafio nos testes visuais é o conteúdo que muda legitimamente.
Mascarando elementos dinâmicos
// Percy
await percySnapshot(page, 'Dashboard', {
percyCSS: `
[data-testid="timestamp"] { visibility: hidden; }
[data-testid="user-avatar"] { filter: blur(10px); }
`,
});
// Playwright integrado
await expect(page).toHaveScreenshot({
mask: [
page.locator('[data-testid="timestamp"]'),
page.locator('.ad-container'),
],
});Aguardando estado estável
test('teste visual do gráfico', async ({ page }) => {
await page.goto('/analytics');
// Aguarda as animações terminarem
await page.waitForLoadState('networkidle');
await page.waitForTimeout(500); // Buffer extra para transições CSS
// Aguarda elemento específico que indica dados carregados
await page.waitForSelector('[data-testid="chart-loaded"]');
await percySnapshot(page, 'Dashboard de Analytics');
});Congelando o tempo
// Congela Date para que timestamps não mudem entre execuções
await page.addInitScript(() => {
const fixedDate = new Date('2026-01-15T12:00:00Z');
Date.now = () => fixedDate.getTime();
Date = class extends Date {
constructor(...args) {
if (args.length === 0) {
super(fixedDate.getTime());
} else {
super(...args);
}
}
};
});Testes visuais no nível de componente
Em vez de screenshots de página inteira, teste componentes individuais:
test('teste visual de variantes de botão', async ({ page }) => {
await page.goto('/storybook/button');
// Testa cada variante do botão
const variants = ['primary', 'secondary', 'danger', 'ghost'];
for (const variant of variants) {
await page.click(`[data-story="${variant}"]`);
await percySnapshot(page, `Botão - ${variant}`);
}
});Testes de componente são mais estáveis do que página inteira: menos partes móveis, mais fácil isolar o que mudou.
Configurando um fluxo de testes visuais
1. Criação do baseline
A primeira execução cria as screenshots de baseline. Revise-as com cuidado: "aprove" apenas os visuais corretos.
2. Fluxo no PR
- Desenvolvedor faz mudanças
- CI roda os testes visuais
- Diffs são postados no PR
- QA ou desenvolvedor revisa os diffs
- Aprova mudanças esperadas (nova feature parece certa), rejeita as inesperadas (bug)
3. Atualizando baselines
Quando você muda a UI intencionalmente, precisa atualizar os baselines:
- Percy: aprove os diffs no dashboard do Percy
- Playwright: rode com a flag
--update-snapshots
npx playwright test --update-snapshotsFaça commit das screenshots atualizadas junto com o PR.
Comparação de custos
| Ferramenta | Tier gratuito | Pago |
|------------|---------------|------|
| Playwright integrado | Gratuito (open source) | Gratuito |
| Percy | 5.000 screenshots/mês | $99+/mês |
| Applitools | Trial limitado | Preço customizado |
| Chromatic | 5.000 snapshots/mês | $149+/mês |
Para projetos pequenos: o integrado do Playwright com mascaramento e ajuste de limiar.
Para times com entregas frequentes: Percy ou Applitools, a revisão de diffs com IA economiza horas de comparação manual.
Resumo
| Abordagem | Precisão | Custo | Melhor para |
|-----------|----------|-------|-------------|
| Playwright integrado | Pixel a pixel | Gratuito | Páginas estáticas, ambiente controlado |
| Percy | Com IA | $99+/mês | Cross-browser, revisão em equipe |
| Applitools | Visual AI + grid | Customizado | Enterprise, multi-browser |
Princípios chave:
- Mascare conteúdo dinâmico (timestamps, anúncios, avatares)
- Aguarde estado estável antes das screenshots
- Revise os baselines com cuidado antes de aprovar
- Agrupe testes visuais por página ou componente para revisão mais fácil
Testes visuais com IA não eliminam os falsos positivos: os reduzem drasticamente. Os diffs restantes que chegam à fase de revisão têm muito mais probabilidade de ser problemas reais.
→ Veja também: Testes de Regressão Visual com Playwright: toHaveScreenshot sem Applitools | Assertions no Playwright: O Guia Completo | Testes Cross-Browser com Playwright: Chrome, Firefox, Safari