Resumen del build
Snapshots totales
108
4 páginas × 3 viewports × 9 estados
Aprobados
102
Sin diff respecto a baseline
Regresiones
6
Requieren revisión manual
Tiempo CI
2m34s
Playwright paralelo × 4 workers
Pipeline de CI — GitHub Actions
npm ci
build app
playwright tests
percy snapshots
visual diff
PR check
Comando:
PERCY_TOKEN configurado como GitHub Secret · rama protegida: main
npx percy exec -- playwright test --project=chromiumPERCY_TOKEN configurado como GitHub Secret · rama protegida: main
Snapshots por página
Configuración de viewports
CSS overrides activos (.percy.yml)
Ejemplo de regresión detectada — /plans · table view · Desktop
La tipografía de cabeceras de tabla cambió de
Inter 14px/600 a Plus Jakarta Sans 13px/700 · diff 4.7%
BEFORE (baseline)
Inter 14px 600
AFTER (feat/rebrand)
Plus Jakarta 13px 700
DIFF (4.7%)
pixels alterados
Checklist de implementación
-
@percy/cli + @percy/playwright instalados como devDependenciesnpm install --save-dev @percy/cli @percy/playwright
-
.percy.yml configurado con widths 375/768/1280 y CSS overridesanimations, transitions y timestamps desactivados
-
tests/visual.spec.ts con percySnapshot en 4 páginas críticas/dashboard · /plans · /patients/:id · /login
-
GitHub Actions workflow con PERCY_TOKEN secret.github/workflows/percy.yml · on: [push, pull_request]
-
Baseline inicial establecida desde rama mainPERCY_TOKEN=xxx npx percy exec -- playwright test
-
Aprobar / rechazar regresiones en Percy dashboard6 snapshots pendientes de revisión en app.percy.io
Archivos generados
⚙️
.percy.yml
✓ activo
version: 2 snapshot: widths: [375, 768, 1280] min-height: 1024 percy-css: | .animation, [data-animated] { animation: none !important; transition: none !important; } .timestamp, .chart-tooltip { visibility: hidden; } discovery: network-idle-timeout: 500 disable-cache: true
🎭
tests/visual.spec.ts
✓ activo
import { test } from '@playwright/test'; import percySnapshot from '@percy/playwright'; const PAGES = [ { path: '/dashboard', name: 'Dashboard' }, { path: '/plans', name: 'Plans' }, { path: '/patients/123', name: 'Patient' }, { path: '/login', name: 'Login' }, ]; for (const { path, name } of PAGES) { test(`Visual: ${name}`, async ({ page }) => { await page.goto(path); await page.waitForLoadState('networkidle'); await percySnapshot(page, name); }); }