Pasa o falla no alcanza: cómo se deciden 14 veredictos
Una prueba en rojo debería significar que la aplicación está rota. Cuando el rojo también puede significar que el DNS parpadeó, que el sitio mostró un CAPTCHA o que el navegador murió, el equipo aprende a relanzar los rojos en vez de leerlos, y el defecto real se esconde en el ruido. Nexus Studio da a cada ejecución uno de 14 veredictos en lugar de dos. Esta página explica cómo elige el motor, en el orden en que decide, y dónde tiene límites el método.
Por el equipo de Nexus Studio, Verdict System LLC. 7 de octubre de 2026.
Tres preguntas, en orden
- ¿La prueba produjo algún resultado?
- Si pasó, ¿pasó limpia?
- Si falló, ¿de quién es la culpa: del arnés, del entorno o de la aplicación?
Solo una respuesta es un reporte de bug: un fallo que pertenece a la aplicación. Cualquier otra respuesta es información sobre otra cosa, y recibe un nombre que lo dice.
Sin resultado no es un resultado
Tres estados no están entre los 14, porque ninguno dice nada de tu aplicación: SKIPPED (la prueba nunca corrió), INTERRUPTED (la detuvo un Ctrl+C, un corte de --max-failures o un timeout global) y CONFIG_ERROR (el arnés no pudo iniciarla). Ninguno archiva una carpeta de evidencia ni una fila en History.
INTERRUPTED existe por una razón concreta. Sin él, una prueba detenida caía en la rama de pase y quedaba registrada como SECURE: un veredicto verde para una prueba que nunca terminó.
Cómo se califica un pase
- SECURE: pasó al primer intento y no se reparó nada.
- AUTO_RECOVER: pasó, pero el self-healing tuvo que reemplazar un selector en esta prueba. El localizador que escribió el autor está muerto, y el próximo cambio en la página rompe la suite de verdad, así que un pase reparado nunca se reporta como limpio. Corrige el selector original.
- FLAKY: falló, luego un reintento pasó, y no se reparó nada. Algo es inestable, en la aplicación o en la prueba, y nada se corrigió.
Una excepción: cuando el primer intento falló solo porque se quedó sin tiempo y el reintento pasó, el veredicto es SECURE. Ese pase muestra latencia, no inestabilidad.
Cómo se asigna un fallo
Cuando una prueba falla, el motor lee el mensaje de error y el registro de red de la ejecución y los compara con grupos de patrones en un orden fijo. El primer grupo que coincide decide el veredicto, así que el orden es parte del diseño.
- CONFIG_ERROR primero:
Cannot find module, unReferenceErroroSyntaxError, una variable de entorno que falta, un fixture que falló en el setup. Si el arnés nunca arrancó, cualquier síntoma posterior es consecuencia de eso. Los patrones son estrechos a propósito, limitados a errores que solo el código de la prueba o su entorno pueden producir: un CONFIG_ERROR de más culparía al arnés de un bug real de tu aplicación. - CRASHED:
Target closed,Page crashed, un error del protocolo de DevTools,SessionNotCreatedError, un id de sesión inválido. El navegador o el driver murió. Es infraestructura: revisa la máquina y el driver. - BLOCKED: un 403 o un 429 en el error o en el registro de red, un CAPTCHA, una página de acceso denegado o un desafío antibot que el motor reconoció en pantalla. El sitio se defendió, y la petición nunca llegó a tu producto.
- UNREACHABLE: la red dijo que no antes de observar ninguna página: el nombre no resolvió (
net::ERR_NAME_NOT_RESOLVEDen Chromium,NS_ERROR_UNKNOWN_HOSTen Firefox,Could not resolve hostnameen WebKit), la conexión fue rechazada o la máquina estaba sin conexión. Un error de certificado no está aquí: ese es un hallazgo. - TIMEOUT: el
Timeout 30000ms exceededde Playwright, elWait timed out afterde Selenium, unTimeoutErroro una prueba que Playwright marcó como agotada. Una navegación que se quedó sin tiempo es TIMEOUT, no UNREACHABLE: empezó, y la página fue lenta. - BREACHED_FLAKY: nada de lo anterior lo explica, y la prueba ya se había reintentado. Falló, y el fallo mismo es inconsistente. Compara los intentos antes de reportar un bug.
- BREACHED: nada de lo anterior lo explica, en un solo intento. Falló una aserción, y ningún patrón de entorno ni de arnés explica el error. Este es el reporte de bug.
Cada grupo cubre la redacción de Playwright y la de Selenium WebDriver. Antes de que existieran los patrones de Selenium, un TimeoutError de WebDriver y el SessionNotCreatedError de un chromedriver desactualizado salían como BREACHED, como si la aplicación tuviera un defecto.
Un teléfono Android real que no puede tomar la ejecución, porque se durmió o está bloqueado, también es BLOCKED: un requisito sin cumplir, no un fallo del producto. La regla salió de un caso medido. Un teléfono se durmió a mitad de una campaña, y una prueba de login que había pasado cuatro veces seguidas salió en rojo crítico.
Ejecuciones con caos
Cuando la ejecución inyecta fallas desde Chaos Lab, el veredicto responde otra pregunta: ¿la aplicación aguantó? Un pase, SECURE o AUTO_RECOVER, se vuelve CHAOS_RESILIENT. Todo lo demás se vuelve CHAOS_BREACHED, incluidos un pase FLAKY y un TIMEOUT, porque bajo una falla inyectada ese es el impacto. SKIPPED, INTERRUPTED y CONFIG_ERROR quedan como están: una prueba que no corrió no dice nada de resiliencia.
Comprobaciones estrictas que pueden cambiar un pase
Tres comprobaciones corren junto a tus aserciones: cabeceras de seguridad, accesibilidad con axe-core y presupuestos de rendimiento de Web Vitals y lazy loading. Registran lo que encuentran en cada ejecución. Cambian el veredicto solo cuando las haces estrictas en Settings. En una aplicación existente, cualquiera de ellas pondría toda la suite en rojo el primer día, y una suite siempre en rojo es una suite que nadie lee.
Cuando son estrictas, se aplican solo a una prueba que pasó, en este orden: SECURITY_VIOLATION, A11Y_VIOLATION, PERFORMANCE_DEGRADED. Seguridad va primero porque, de las tres, es la que puede terminar en un incidente y no en una queja. Una prueba fallida nunca se escala: BREACHED ya dice algo más grave, y un aviso encima ocultaría el hallazgo.
Lo que ve el CI
Los siete veredictos que pasan salen con 0: SECURE, AUTO_RECOVER, FLAKY, CHAOS_RESILIENT, PERFORMANCE_DEGRADED, A11Y_VIOLATION y SECURITY_VIOLATION. Una reserva se ve en el informe y en History, no como un build roto. Los otros siete salen con 1. Los runners de pytest y Selenium salen con 2 cuando la ejecución no pudo ni arrancar, por ejemplo sin Python o con un navegador para el que el motor no tiene driver.
Límites del método
- La clasificación lee el texto del error. Un mensaje que escribiste tú y que contiene
403,ForbiddenoAccess Deniedse lee como BLOCKED, y un error que contieneis not a functionse lee como CONFIG_ERROR. Mantén específicos los mensajes de tus aserciones, y abre metadata.json cuando un veredicto te sorprenda. - Un TIMEOUT no prueba que la aplicación funcione. Dice que la ejecución no puede saberlo. Una prueba que agota el tiempo en cada ejecución merece una revisión.
- Los reintentos son lo que separa FLAKY de SECURE y BREACHED_FLAKY de BREACHED. Sin reintentos, un fallo intermitente es un BREACHED.
- Las pruebas de API tienen siete veredictos propios, decididos con otras reglas: ver pruebas de API.
Verlo en un fallo real
La página de evidencia sigue una prueba fallida y lista cada archivo que cada veredicto deja en tu disco: report.md, metadata.json, raw-data.json, una captura y, en un fallo real, el video. La prueba de 30 días corre el mismo motor sobre tus propias pruebas.