Files
Autonomous-Bug-Explorer/.ralph/specs/legacy/visual-regression.md

3.9 KiB

ABE — Visual Regression Testing Specification

Concepto

ABE toma screenshots durante la exploración. En vez de solo guardarlos, los compara contra una baseline aprobada para detectar cambios visuales inesperados entre ejecuciones. Inspirado en Percy y Chromatic, pero integrado directamente en el flujo de exploración autónoma.

Cómo funciona

Primera ejecución (sin baseline)

  1. ABE explora el app, toma screenshots de cada estado descubierto
  2. Todos los screenshots se marcan como "pending review" en la UI
  3. El usuario aprueba o rechaza cada uno desde la GUI
  4. Los aprobados se convierten en la BASELINE

Ejecuciones posteriores

  1. ABE explora el app, toma screenshots de cada estado
  2. Para cada screenshot, busca la baseline correspondiente por state_id (hash DOM+URL)
  3. Si no hay baseline: marcar como "new state", notificar
  4. Si hay baseline: comparar usando pixelmatch (npm library)
  5. Si diff > threshold (default 0.1%): crear anomalía tipo visual_regression
  6. Si diff <= threshold: marcar como "passed"

Librería de comparación

Usar pixelmatch (npm) para comparación pixel a pixel. Usar sharp para resize y normalización de imágenes antes de comparar.

import pixelmatch from 'pixelmatch';
import sharp from 'sharp';

async function compareScreenshots(
  baselinePath: string,
  currentPath: string,
  diffOutputPath: string,
  threshold: number = 0.1
): Promise<{ diffPixels: number; diffPercent: number; hasDiff: boolean }> {
  // resize both to same dimensions, compare, generate diff image
}

Modelo de datos — añadir a SQLite

Table: visual_baselines

CREATE TABLE IF NOT EXISTS visual_baselines (
  id TEXT PRIMARY KEY,
  state_id TEXT NOT NULL,
  url TEXT NOT NULL,
  screenshot_path TEXT NOT NULL,
  approved_at INTEGER NOT NULL,
  approved_by TEXT DEFAULT 'user',
  width INTEGER NOT NULL,
  height INTEGER NOT NULL
);

Table: visual_comparisons

CREATE TABLE IF NOT EXISTS visual_comparisons (
  id TEXT PRIMARY KEY,
  session_id TEXT NOT NULL,
  state_id TEXT NOT NULL,
  baseline_id TEXT,
  current_screenshot_path TEXT NOT NULL,
  diff_screenshot_path TEXT,
  diff_pixels INTEGER,
  diff_percent REAL,
  status TEXT NOT NULL,  -- 'passed' | 'failed' | 'new_state' | 'pending'
  created_at INTEGER NOT NULL
);

Nuevo tipo de anomalía

Añadir a AnomalyDetector:

  • type: visual_regression
  • severity: calculado por diff_percent:
    • < 1% → low
    • 1-5% → medium
    • 5-15% → high
    • 15% → critical

  • description: "Visual regression detected: X% of pixels changed"
  • evidence: baseline screenshot + current screenshot + diff image (highlighted in red)

Nuevo endpoint de API

GET /api/visual/comparisons

Lista todas las comparaciones de la sesión más reciente. Query: ?status=failed&sessionId=xxx

POST /api/visual/baselines/:comparisonId/approve

Aprueba un screenshot como nueva baseline.

POST /api/visual/baselines/:comparisonId/reject

Rechaza (anomalía confirmada, no actualizar baseline).

POST /api/visual/baselines/approve-all

Aprueba todos los "new_state" pendientes de una sesión.

Frontend — nueva sección Visual Review

Nueva página /visual-review:

  • Grid de cards, cada una muestra: URL del estado, thumbnail del screenshot actual
  • Filtros: passed | failed | new_state | pending
  • Click en una card abre modal con:
    • Vista lado a lado: baseline izquierda, actual derecha
    • Vista diff: imagen con píxeles cambiados en rojo
    • Porcentaje de cambio
    • Botones: Approve as new baseline | Mark as bug | Ignore
  • Bulk actions: "Approve all new states", "Mark all failed as bugs"

Configuración

Añadir a ExplorationConfig:

visualRegression: {
  enabled: boolean;             // default: true
  threshold: number;            // default: 0.001 (0.1%)
  screenshotFullPage: boolean;  // default: false (solo viewport)
  ignoreSelectors: string[];    // e.g. [".timestamp", ".ad-banner"] — excluir zonas dinámicas
}