Un flaky test o test inestable es, según la definición de Playwright, el que falló en la primera ejecución pero pasó al reintentarlo. Su costo real no es el minuto perdido: es que el equipo deja de creerle a la suite y adopta el hábito de reejecutar sin mirar, que es exactamente lo que hace pasar un fallo verdadero. El procedimiento tiene cuatro pasos en orden: medir cuáles son y con qué frecuencia fallan, diagnosticar con la evidencia de la ejecución fallida —traza, video, capturas—, arreglar la causa entre las seis típicas, y solo como último recurso cuarentena, con fecha y responsable. Los reintentos sirven para medir el problema, no para curarlo.
Ver índice de contenidos
- 01Qué es, con precisión
- 02Por qué es más caro de lo que parece
- 03Paso 1: medir
- 04Los reintentos, bien entendidos
- 05Paso 2: diagnosticar
- 06Las seis causas y su arreglo
- 07Cuando el problema no es el test
- 08Aislamiento: la prevención que funciona
- 09Paso 4: cuarentena, con condiciones
- 10Errores frecuentes
- 11Preguntas frecuentes
- 12Fuentes
Qué es, con precisión
Las dos herramientas más usadas lo definen desde ángulos distintos y complementarios.
Playwright da la definición operativa, la que se puede automatizar: un test inestable es el que «falló en la primera ejecución, pero pasó al reintentarlo». De ahí salen sus tres categorías de resultado: passed para los que pasaron a la primera, flaky para los que fallaron y pasaron al reintento, y failed para los que fallaron en todos los intentos.
Cypress lo define por su origen: tests que «fallan debido a condiciones impredecibles», y enumera las sospechosas habituales —animaciones, llamadas a APIs, disponibilidad del servidor o de la base de datos, dependencias de recursos y problemas de red—. También marca como Flaky a los tests que reintentaron y después pasaron.
La consecuencia de que exista una definición operativa
Que la inestabilidad se puede medir sin discusión. No hace falta que alguien opine si un test «es medio inestable»: con reintentos activados, la herramienta lo etiqueta sola. Eso convierte un problema difuso —«la suite está inestable»— en una lista concreta de nombres de test con una frecuencia asociada, y una lista se puede trabajar.
Por qué es más caro de lo que parece
El costo visible es chico: unos minutos de reejecución. El costo real es de otro orden y llega por tres vías.
Primera: se rompe la señal. Una suite existe para responder una pregunta binaria —¿este cambio rompió algo?—. Cuando el rojo puede significar «rompiste algo» o «mala suerte», la respuesta deja de ser información y pasa a ser una probabilidad, que es mucho menos útil.
Segunda: se entrena el reflejo equivocado. Un equipo que convive con tests inestables aprende, con toda lógica, a reejecutar antes de investigar. Ese hábito funciona el 95 % de las veces y falla catastróficamente el 5 % restante: el día que el rojo era real, también se reejecutó y también se ignoró.
Tercera: se detiene el crecimiento de la suite. Cuando agregar tests significa agregar ruido, el equipo deja de agregar tests. La inestabilidad no solo daña la suite que existe: impide la que debería existir.
Paso 1: medir
El error más común es empezar por el arreglo. Sin medición no hay problema definido: hay una sensación compartida de que «la suite anda mal», que no se puede priorizar ni saber si mejoró.
Lo mínimo que hace falta para tener datos:
- Activá los reintentos en integración continuaEn Playwright, con
--retries=3o desde la configuración. En Cypress, conrunMode, cuyo valor por defecto es 0. Con eso, la herramienta empieza a etiquetar qué tests son inestables. - Guardá los resultados de cada ejecuciónNo solo el último. Un test que falla una vez cada veinte ejecuciones no aparece en una sola corrida, y suele ser el peor de todos.
- Armá la lista ordenada por frecuenciaQué test, cuántas veces de cuántas, desde cuándo. Esa tabla es el punto de partida y también la forma de demostrar que el trabajo sirvió.
- Fijá un objetivo explícitoPor ejemplo: ningún test con más del 1 % de inestabilidad en la rama principal. Sin objetivo, la tarea no termina nunca.
Los reintentos, bien entendidos
Acá está el malentendido que hace que el problema se vuelva crónico en muchos equipos. Los reintentos son una herramienta de medición, no un arreglo.
| Uso | Qué produce |
|---|---|
| Como medición: activados, con la etiqueta «inestable» revisada cada semana | Una lista de tests para arreglar y un indicador que se puede seguir |
| Como solución: activados y nadie mira la etiqueta | Una suite verde que ya no distingue un fallo real de uno intermitente |
Vale la pena entender cómo funcionan por dentro, porque explica algo importante. Playwright, cuando un test falla, «descarta el proceso de trabajo completo junto con el navegador e inicia uno nuevo», y el proceso nuevo empieza reintentando el test que falló. La documentación señala por qué: «este esquema funciona perfectamente para tests independientes y garantiza que los tests que fallan no puedan afectar a los sanos».
Leído al revés, eso es una advertencia: el esquema funciona para tests independientes. Si tus tests dependen entre sí, descartar el proceso y reintentar uno solo puede producir resultados incoherentes, porque el estado que ese test necesitaba lo dejaba otro.
Los dos marcos permiten además acotar los reintentos a un grupo: en Playwright, con test.describe.configure({ retries: 2 }) para «un grupo específico de tests o un solo archivo». Eso es preferible a subir los reintentos globales, porque mantiene visible dónde está la deuda.
Paso 2: diagnosticar
El instinto es reproducirlo localmente. Casi nunca funciona: si el test falla una vez cada treinta ejecuciones y depende de la velocidad de la máquina de integración continua, en tu equipo va a pasar siempre.
La estrategia que sí funciona es diagnosticar con la evidencia que dejó la ejecución que falló. Para eso hay que configurarla antes:
- Traza de la ejecución. Es la herramienta más útil de todas: permite ver, paso a paso, el estado exacto de la página en el momento en que la aserción falló, con el DOM, la consola y las peticiones de red. Conviene configurarla para que se guarde en el primer reintento.
- Video y capturas de pantalla en los fallos. Más burdo que la traza, pero responde rápido la pregunta «¿qué estaba en pantalla?».
- Registros del sistema bajo prueba. Del mismo intervalo de tiempo. Es lo que distingue un problema del test de un problema del producto.
- Los artefactos conservados. Si tu integración continua borra los artefactos de las ejecuciones anteriores, estás tirando la única evidencia que tenías.
Y cuatro diferencias del entorno que explican la mayoría de los casos de «solo falla en CI»:
| Diferencia | Qué inestabilidad produce |
|---|---|
| La máquina de CI es más lenta y más cargada | Todo lo que dependía de tiempos empieza a fallar |
| Los tests corren en paralelo | Aparecen los conflictos por estado compartido |
| Zona horaria y configuración regional distintas | Fallos en fechas, formatos de número y ordenamientos |
| Los datos de partida no son los mismos | Tests que dependían de un registro que en CI no existe |
Las seis causas y su arreglo
1. Esperas por tiempo fijo
La causa número uno, con diferencia. Una pausa de dos segundos funciona hasta el día que algo tarda tres. El arreglo es esperar por condición en lugar de por tiempo: que el elemento esté visible, habilitado, con el texto buscado o desaparecido.
// Frágil: apuesta a que dos segundos alcanzan
await page.waitForTimeout(2000);
await expect(page.getByText('Pedido confirmado')).toBeVisible();
// Estable: espera a que la condición se cumpla, con su propio límite
await expect(page.getByText('Pedido confirmado')).toBeVisible();La buena noticia es que las aserciones modernas de Playwright y Cypress ya esperan por condición. En la mayoría de los casos, el arreglo consiste en borrar las pausas manuales y confiar en la aserción tal como está diseñada.
2. Dependencia entre tests
El test B usa el registro que creó el test A. Funciona mientras el orden se mantenga, y se rompe al paralelizar, al reintentar uno solo o al ejecutar un archivo aislado. El arreglo: cada test crea lo que necesita y no supone nada del anterior.
3. Estado compartido
Un usuario de prueba, un producto, una configuración global que varios tests modifican. En paralelo, se pisan. El arreglo: datos propios por test, con identificadores únicos generados en el momento.
4. Fecha, hora y zona horaria
El clásico que pasa todo el año y falla el último día del mes, o a medianoche, o cuando cambia la hora. El arreglo: controlar el reloj con las utilidades que traen los marcos, o usar fechas relativas al momento de la ejecución en lugar de fechas fijas.
5. Servicios externos
Una API de terceros lenta, caída o con límite de peticiones. Cypress la nombra entre las condiciones impredecibles. El arreglo: simular la respuesta en los tests que no están probando esa integración. Los que sí la prueban, aislados y con la expectativa de que fallen por causas ajenas.
6. Condiciones de carrera en la interfaz
Animaciones a mitad de camino, contenido que se carga en dos etapas, elementos que se vuelven a montar y dejan inválida la referencia. El arreglo: esperar el estado final observable —el resultado, no el paso intermedio— y, si el marco lo permite, desactivar animaciones en el entorno de prueba.
Cuando el problema no es el test
Un test que falla de manera intermitente puede estar detectando un defecto intermitente real. Una condición de carrera en la aplicación, una consulta que a veces devuelve los resultados en otro orden, un bloqueo esporádico en la base de datos, una caché que a veces no se invalida: todo eso se manifiesta exactamente igual que un test inestable. Estabilizar el test en ese caso es la peor forma posible de cerrar el caso, porque se elimina la única alarma que estaba funcionando.
De ahí que la primera pregunta ante un test que falla y luego pasa no sea «¿cómo lo estabilizo?» sino «¿esto es del test o del producto?». Dos señales que apuntan al producto:
- El fallo no es siempre el mismo. Un test inestable típico falla en el mismo punto; un defecto real suele producir fallos variados.
- Los registros del sistema muestran algo raro en ese momento. Un error, un tiempo de espera agotado, una excepción. Un test inestable por esperas no deja rastro en el servidor.
Aislamiento: la prevención que funciona
Casi todas las causas anteriores son variantes de un mismo problema de fondo: falta de aislamiento. Y eso se puede prevenir con cuatro reglas que valen la pena como acuerdo de equipo:
- Cada test crea los datos que necesita y los identifica de forma única.
- Ningún test depende del orden de ejecución ni del resultado de otro.
- Todo lo externo al sistema bajo prueba está simulado, salvo en los tests que prueban justamente esa integración.
- Nada que dependa del reloj real, de la zona horaria de la máquina o de una pausa fija.
Una prueba de que el aislamiento está bien: la suite tiene que dar el mismo resultado ejecutada en orden aleatorio. Si al aleatorizar el orden aparecen fallos, hay dependencias ocultas, y esa es una forma barata de encontrarlas antes de que se manifiesten solas.
Paso 4: cuarentena, con condiciones
A veces un test inestable bloquea al equipo y no hay tiempo de arreglarlo. La cuarentena es la salida legítima, y consiste en sacarlo del conjunto que puede detener el pipeline pero seguir ejecutándolo y registrando su resultado. Esa segunda mitad es la que hace la diferencia con apagarlo.
Dos condiciones que no son negociables si no querés que la cuarentena se convierta en un cementerio:
- Fecha límite. Anotada donde se vea. Un test en cuarentena sin fecha es un test eliminado con más pasos.
- Responsable. Una persona con nombre, no «el equipo».
Y un límite de cantidad que funciona como alarma: si hay más de un puñado de tests en cuarentena al mismo tiempo, el problema ya no son los tests sino la suite o el entorno, y conviene parar a resolver eso en lugar de seguir mandando casos a la lista.
Errores frecuentes
- Subir los reintentos hasta que la suite quede verde. Es la forma más eficiente de perder toda la información que la suite podía dar.
- Agregar una pausa fija para «estabilizar». Funciona hoy, falla en un mes y hace la suite más lenta para siempre.
- Intentar reproducirlo localmente antes de mirar la traza. Se pierde una tarde en algo que la evidencia respondía en cinco minutos.
- Apagar el test en lugar de ponerlo en cuarentena. Se pierde la visibilidad y a nadie le consta qué dejó de cubrirse.
- No aleatorizar el orden nunca. Las dependencias entre tests quedan latentes hasta que se manifiestan de la peor manera.
- Suponer que la culpa es siempre del test. A veces es del producto, y ahí estabilizarlo es tapar un defecto.
- Tratarlo como tarea individual. Sin un acuerdo de equipo sobre aislamiento, cada test nuevo reintroduce el problema.
Preguntas frecuentes
¿Qué es exactamente un flaky test?
Playwright da la definición operativa más útil: un test inestable es el que falló en la primera ejecución pero pasó al reintentarlo. Eso permite clasificar cada test en tres categorías: aprobado, inestable y fallido. Cypress lo describe desde la causa, como un test que falla por condiciones impredecibles: animaciones, llamadas a APIs, disponibilidad del servidor o de la base de datos, dependencias de recursos y problemas de red. Las dos definiciones son compatibles y describen lo mismo desde ángulos distintos: el síntoma y el origen.
¿Está mal activar los reintentos?
No, y de hecho conviene activarlos, pero por un motivo distinto del que la mayoría cree: sirven para medir el problema, no para resolverlo. Con reintentos activados, la herramienta empieza a marcar qué tests son inestables y con qué frecuencia, y eso te da la lista que hace falta para trabajar. El problema aparece cuando los reintentos se usan como solución: ahí la suite queda en verde y un fallo real intermitente se vuelve indistinguible de un test inestable, que es exactamente la situación que hay que evitar.
¿Cuál es la causa más común de inestabilidad?
Las esperas por tiempo fijo. Poner una pausa de dos segundos funciona hasta el día que la red, la máquina de integración continua o la base de datos tardan tres. La corrección es reemplazarlas por esperas por condición: en lugar de esperar un tiempo, esperar a que el elemento esté visible, habilitado o con el texto buscado. Playwright y Cypress traen ese comportamiento incorporado en sus aserciones, así que en la mayoría de los casos alcanza con dejar de poner pausas manuales y usar las aserciones tal como están diseñadas.
¿Cómo se diagnostica un test que solo falla en integración continua?
Con la evidencia que dejó la ejecución que falló, no reproduciéndolo localmente, que es lo que casi nadie logra. Eso implica configurar la suite para guardar traza, video y capturas de pantalla en los fallos y reintentos, y conservar esos artefactos. Una traza permite ver exactamente en qué estado estaba la página cuando la aserción falló, que es la información que resuelve la mayoría de los casos. Y conviene revisar cuatro diferencias del entorno: velocidad de la máquina, paralelismo, zona horaria y datos disponibles.
¿Cuándo conviene poner un test en cuarentena?
Cuando bloquea al equipo y no hay tiempo de arreglarlo en el momento, y siempre con dos condiciones: fecha límite y responsable. La cuarentena consiste en sacarlo del conjunto que puede detener el pipeline, pero seguir ejecutándolo y registrando su resultado, para que quede visible. Sin fecha ni responsable, la cuarentena se convierte en el cementerio donde van los tests que nadie va a volver a mirar, y a los seis meses hay veinte tests apagados que nadie sabe si cubren algo importante.
¿Un test inestable puede estar señalando un problema real del producto?
Sí, y es la posibilidad que más se pasa por alto porque es la más incómoda. Una condición de carrera real en la aplicación, una consulta que a veces devuelve resultados en otro orden o un bloqueo esporádico en la base de datos se manifiestan exactamente como un test inestable: fallan a veces. Por eso la primera pregunta ante un test que falla y luego pasa no es «¿cómo lo estabilizo?» sino «¿esto es del test o del producto?». Estabilizar un test que estaba detectando un defecto intermitente es la peor forma de cerrar el caso.
Fuentes
Documentación oficial y material de la comunidad consultados para esta guía. Fecha de consulta: 27 de julio de 2026.
Aportes de la comunidad Underc0de
- Underc0de, foro. Overrides y mocking en DevTools, o cómo crear tu propio set de datos, por 0d1n, sección QA y Testing, 20 de febrero de 2025. Técnicas para controlar los datos de prueba, que es la base del aislamiento.
- Underc0de, foro. Ayuda con Cypress, sección QA y Testing, 11 de julio de 2024.
- Underc0de, foro. Sección QA y Testing. Hilos de la comunidad sobre automatización y herramientas de prueba.
Documentación oficial
- Playwright. Retries. Definición de test inestable, las tres categorías de resultado, el descarte del proceso de trabajo al fallar, la nota sobre tests independientes y la configuración por grupo.
- Cypress. Test Retries. Descripción de los tests inestables por sus causas impredecibles, configuración de
runModeyopenModecon valor por defecto 0, y etiquetado de los tests que reintentaron y pasaron. - Playwright. Trace viewer. La herramienta de traza usada para diagnosticar con la evidencia de la ejecución fallida.