Haz que un test inestable falle diez veces a propósito
¿Test inestable (flaky)? Hazlo fallar diez veces a propósito. Un test que falla una vez en CI y pasa al reintentar puede desperdiciar una semana de re-ejecuciones mientras el equipo discute si es real. La solución empieza con un comando: corre el spec sospechoso repetidamente en tu propia máquina hasta que la falla sea aburrida y reproducible — y entonces depúrala como cualquier otro bug.
Por qué los reintentos ocultan bugs reales
Un reintento que convierte rojo en verde no arregla nada — solo lo reclasifica. Playwright incluso los reporta como una categoría aparte: un test que falla y luego pasa al reintentar se marca como flaky, no como aprobado. Cada pase "flaky" es una condición de carrera, un timeout o un bug de orden que igual llegó a producción. Y como iterar sobre fallas de CI es lento (push, cola, esperar 15 minutos, leer logs), los equipos racionalizan en vez de reproducir: "la infra estaba lenta", "córrelo de nuevo". Diez corridas locales en menos de un minuto terminan esa discusión con datos.
El comando
Apunta Playwright al archivo sospechoso y repítelo:
npx playwright test tests/checkout.spec.ts --repeat-each=10
--repeat-each ejecuta cada test que coincida N veces (por defecto 1). Si es inestable, una falla intermitente que aparece 1 de cada 20 veces en CI normalmente se manifiesta en segundos en tu máquina — ahora tienes un ciclo determinista en vez de un debate.
Ajusta aún más el ciclo:
| Flag | Qué hace | Cuándo agregarlo |
|---|---|---|
--repeat-each=10 | Ejecuta cada test N veces (por defecto 1) | Siempre — este es el tip |
-g "adds to cart" | Solo corre tests que coinciden con una regex | Acotar a un solo test, no al archivo |
--workers=1 | Un solo worker, sin paralelismo | Descartar o confirmar interferencia paralela |
--retries=0 | Cero reintentos (el valor por defecto) | Asegurar que nada enmascare la falla |
--trace=retain-on-failure | Conserva el trace completo de las corridas fallidas | Obtener la línea de tiempo de la falla |
--headed | Corre con navegadores visibles | Ver la condición de carrera en vivo |
Compara dos corridas: --repeat-each=10 --workers=1 contra --repeat-each=10 con los workers por defecto. ¿Falla solo con paralelismo? Hay estado compartido entre tests. ¿Falla de las dos formas? El bug está dentro del test o de la app — casi siempre una espera faltante o una carrera real.
Arregla la carrera, no el síntoma
Cuando ya falla a demanda, el modo de falla suele ser uno de tres: el test hace la aserción antes de que la app se estabilice (arregla la condición de espera, no agregues un sleep), dos tests comparten estado (aísla el fixture), o la app tiene una carrera real (felicidades — el test inestable hizo su trabajo). --trace=retain-on-failure te da el trace paso a paso de exactamente las corridas que fallaron.
La cuarentena es el último recurso, no el primero. Si debes estacionar un test, test.fixme() de Playwright lo marca como fallido y omite su ejecución — visible en los reportes, a diferencia de un test borrado — y test.fail() lo ejecuta verificando que efectivamente falle, así te enteras en cuanto el bug desaparezca. Abre el issue al poner el test en cuarentena; un fixme sin dueño es un borrado con pasos extra.
Nivel experto: la misma jugada en cualquier stack
- pytest — el plugin
pytest-repeatagrega--count:pytest --count=10 test_checkout.py, más@pytest.mark.repeat(10)para un test puntual y--repeat-scope(function/class/module/session) para controlar el orden. - Go —
go test -count=10 -run TestCheckout ./...corre el test diez veces;-count=1solo también es la forma idiomática de saltarse la caché de resultados de Go. Agrega-racey muchas veces obtienes la carrera de datos localizada gratis. - Puerta de CI — corre
--repeat-eachsobre archivos de test nuevos en CI antes del merge. Un test que no aguanta 10 corridas consecutivas el primer día no se vuelve más estable con el tiempo. - Ángulo AI-coding — los tests generados por agentes son una fuente común de inestabilidad (las esperas generadas son optimistas). Haz que "pasa
--repeat-each=10" sea parte de tu ciclo de aceptación antes de commitear cualquier cosa que escribió un agente.
Recursos
- Referencia del CLI de Playwright test —
--repeat-each,--workers,--trace - Reintentos en Playwright test — cómo se detecta y reporta lo flaky
- Anotaciones de Playwright —
test.fixme(),test.fail() - pytest-repeat —
--county--repeat-scope - Flags de testing del comando go —
-count
¿Construyendo una funcionalidad con IA? Yeda AI diseña, audita y lleva a producción sistemas LLM.