4.2 KiB
0048 — Visual tests via primitives_gallery (golden screenshots) + CI gate para nuevas funciones
Metadata
| Campo | Valor |
|---|---|
| ID | 0048 |
| Estado | pendiente |
| Prioridad | media |
| Tipo | feature — testing infra + CI |
Dependencias
Bloquea-por: 0047 (Catch2 montado).
Objetivo
- Anadir captura automatica de screenshots por demo en
primitives_gallery, comparados pixel-a-pixel contra goldens encpp/tests/golden/. Cada PR que toque un primitivo de UI muestra el diff. - CI gate: PR que anada funcion nueva en
cpp/functions/exigetested: trueen el.md.
Contexto
primitives_gallery ya renderiza cada primitivo del registry con datos sinteticos. Si capturamos PNGs por demo y los comparamos con goldens commiteados, tenemos test visual automatico para cualquier cambio que afecte a render.
Arquitectura
cpp/
├── apps/primitives_gallery/
│ ├── main.cpp # MOD — flag --capture <out_dir>
│ └── capture.{h,cpp} # NEW — render headless por demo, dump PNG
├── tests/
│ ├── golden/ # NEW
│ │ ├── button.png
│ │ ├── select.png
│ │ ├── kpi_card.png
│ │ └── ... (1 png por demo del gallery)
│ ├── test_visual.cpp # NEW — corre gallery con --capture, compara con golden
│ └── CMakeLists.txt # MOD
└── scripts/
├── run_tests.sh # MOD — incluye visual
└── update_goldens.sh # NEW — regenera goldens
Tareas
Fase 1 — Capture mode en primitives_gallery
1.1 Anadir flag --capture <output_dir>. Cuando esta activo:
- Inicializa GLFW en modo offscreen (
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE)) o usa headless via EGL si esta disponible. - Para cada demo en
k_demos[]: seteag_selected_id, hace 3 frames de warmup (para tooltips/animaciones estables), captura framebuffer conglReadPixels, guarda como PNG viastb_image_write. - Output:
<output_dir>/<demo_id>.png. - Sale tras procesar todas.
1.2 Si
--captureno esta presente: comportamiento normal (interactivo).
Fase 2 — Goldens iniciales
2.1 scripts/update_goldens.sh:
#!/usr/bin/env bash
mkdir -p cpp/tests/golden
./cpp/build/apps/primitives_gallery/primitives_gallery --capture cpp/tests/golden
2.2 Generar y commitear los PNGs como linea base.
Fase 3 — Test visual
3.1 test_visual.cpp (Catch2): para cada demo, lanzar gallery con --capture a un dir temporal, comparar contra cpp/tests/golden/<demo>.png con tolerancia configurable (por defecto: 1% pixels distintos, threshold por canal 5/255).
3.2 Si difiere, fallar con info: expected golden/X.png, actual /tmp/.../X.png, diff Y%.
Fase 4 — CI gate para tested:true
4.1 Crear cpp/scripts/check_tested.sh que valida:
sqlite3 registry.db "SELECT id FROM functions
WHERE lang='cpp' AND tested=0 AND created_at > date('now','-30 days')"
Si hay alguno → exit 1 con mensaje "anade test antes de mergear".
4.2 Ganchar en cpp/scripts/run_tests.sh (post-ctest).
Fase 5 — Documentar en PATTERNS
5.1 En cpp/PATTERNS.md (de 0041) anadir seccion "Tests visuales":
- Como capturar nuevo golden cuando se anade un primitivo (
update_goldens.sh). - Como diagnosticar diff (renderiza el png actual vs golden lado a lado).
Decisiones
- Headless via GLFW invisible es lo simple. Si no funciona en algun entorno, usar EGL/swiftshader como fallback.
- Tolerancia 1% para evitar flakes por antialiasing/font rendering distinto. Ajustable.
- Goldens en repo (PNGs binarios) — pesa poco si los demos son pequenos (200x200 max).
Riesgos
- Diferencias de rendering entre Linux dev y CI: usar mesa software rendering (
LIBGL_ALWAYS_SOFTWARE=1) en ambos lados para consistencia. - Cambios cosmeticos legitimos en primitivos requieren regenerar goldens — flujo:
update_goldens.sh && git diff cpp/tests/golden/para revisar visualmente.
Validacion
cmake --build cpp/build -j
ctest --test-dir cpp/build -R visual --output-on-failure
# Cambia un color en tokens, run otra vez, debe FALLAR.
# update_goldens.sh + git diff muestra los pngs cambiados.