13. Sincronización, esperas y problemas de pruebas inestables

13.1 Introducción

Uno de los mayores desafíos de las pruebas End-to-End es la inestabilidad. Una prueba inestable es aquella que a veces pasa y a veces falla sin que haya cambiado el comportamiento real que queremos validar.

Muchas veces estas fallas aparecen por problemas de sincronización: la prueba intenta hacer una acción antes de que la pantalla esté lista, antes de que termine una petición, antes de que aparezca un elemento o antes de que el sistema actualice su estado.

En este tema veremos qué son las esperas, por qué las pruebas se vuelven inestables y cómo diseñar escenarios E2E más confiables.

13.2 Qué es la sincronización

Sincronizar una prueba significa coordinar sus acciones con el estado real de la aplicación. La prueba debe esperar a que el sistema esté preparado antes de continuar.

Una prueba E2E no debería avanzar porque "ya pasó suficiente tiempo". Debería avanzar porque la condición necesaria se cumplió.

Por ejemplo, después de presionar "Confirmar compra", la prueba no debería buscar inmediatamente el mensaje de éxito si el backend todavía está procesando el pago. Debe esperar una señal clara: mensaje visible, cambio de página, orden creada o estado actualizado.

13.3 Qué es una prueba inestable

Una prueba inestable, también llamada flaky test, produce resultados inconsistentes. Puede fallar en una ejecución y pasar en la siguiente sin cambios en el código.

Ejemplos de síntomas:

  • La prueba falla porque no encuentra un elemento que sí aparece segundos después.
  • El clic se ejecuta antes de que el botón esté habilitado.
  • La prueba verifica datos antes de que se actualice la pantalla.
  • El escenario pasa localmente, pero falla en otro ambiente.
  • Una ejecución paralela modifica los datos que otra prueba espera.

Las pruebas inestables son peligrosas porque reducen la confianza del equipo. Si las fallas se consideran "ruido", se pueden ignorar defectos reales.

13.4 Causas frecuentes de inestabilidad

Las causas pueden estar en la prueba, en el ambiente o en la aplicación. Algunas de las más comunes son:

Causa Ejemplo Consecuencia
Carga asincrónica La pantalla muestra datos después de una petición. La prueba busca elementos antes de que existan.
Esperas fijas Esperar siempre 2 segundos. A veces sobra tiempo y a veces no alcanza.
Datos compartidos Dos pruebas usan el mismo usuario o recurso. Una ejecución altera el estado de la otra.
Servicios lentos Pago, correo o backend responden con demora. El resultado aparece tarde o no aparece a tiempo.
Selectores frágiles La prueba depende de una clase CSS cambiante. Falla aunque el comportamiento sea correcto.
Animaciones Un elemento existe, pero todavía no puede recibir clic. La acción se ejecuta en un momento incorrecto.

13.5 Esperas fijas

Una espera fija consiste en pausar la prueba durante una cantidad determinada de tiempo, por ejemplo tres segundos. Aunque parece una solución rápida, suele ser una fuente de problemas.

Problemas de las esperas fijas:

  • Si el sistema responde más rápido, la prueba pierde tiempo.
  • Si el sistema responde más lento, la prueba falla igual.
  • No explican qué condición se estaba esperando.
  • Aumentan la duración total de la suite.
  • Pueden ocultar problemas reales de rendimiento o estado.
Las esperas fijas deben ser la excepción. Siempre que sea posible, conviene esperar una condición concreta del sistema.

13.6 Esperas basadas en condiciones

Una espera basada en condición espera hasta que ocurra algo específico. Es más clara y más estable que una pausa fija.

Ejemplos de condiciones útiles:

  • Un elemento está visible.
  • Un botón está habilitado.
  • Un mensaje de éxito aparece.
  • La URL cambió a la página esperada.
  • Una tabla contiene el registro creado.
  • El estado de una operación cambió a "aprobada".

La condición debe estar conectada con el flujo. No se trata de esperar cualquier elemento, sino la señal que indica que el sistema está listo para el siguiente paso.

13.7 Esperar elementos visibles no siempre alcanza

Que un elemento esté visible no siempre significa que esté listo para interactuar. Puede estar cubierto por una animación, deshabilitado, cargando datos o esperando una respuesta del servidor.

Antes de interactuar, puede ser necesario confirmar:

  • Que el elemento está visible.
  • Que está habilitado.
  • Que no está cubierto por otro elemento.
  • Que contiene los datos esperados.
  • Que la pantalla terminó de actualizarse.

Por ejemplo, un botón "Confirmar" puede verse en pantalla, pero estar deshabilitado hasta que se calcule el total de la compra.

13.8 Sincronización con peticiones y respuestas

En aplicaciones modernas, muchas acciones dependen de peticiones al backend. La pantalla puede cambiar después de que una API responda, no necesariamente en el instante del clic.

Ejemplos:

  • Buscar productos espera resultados del backend.
  • Confirmar compra espera aprobación del pago.
  • Guardar formulario espera persistencia en base de datos.
  • Cargar una agenda espera disponibilidad de turnos.

Una prueba E2E debe esperar una consecuencia de esas respuestas: datos visibles, mensaje final, cambio de estado o navegación esperada.

13.9 Sincronización con estados del negocio

A veces el elemento visual aparece, pero el estado del negocio todavía no está listo. Por ejemplo, después de enviar una solicitud puede aparecer un mensaje, pero el estado real todavía no fue actualizado por un proceso interno.

En escenarios críticos, conviene verificar señales de negocio:

  • La orden aparece como pagada.
  • El turno figura como reservado.
  • La solicitud queda en estado pendiente.
  • El curso aparece asociado al alumno.
  • La notificación queda registrada o enviada.

Esto permite que la prueba espere el resultado que realmente importa, no solo un cambio superficial de pantalla.

13.10 Timeouts

Un timeout es el tiempo máximo que una prueba espera antes de declarar que algo falló. Los timeouts son necesarios, pero deben elegirse con criterio.

Timeout demasiado corto Timeout demasiado largo
Genera fallas por demoras normales del ambiente. Hace que una falla real tarde mucho en reportarse.
Vuelve la prueba sensible a pequeñas variaciones. Alarga innecesariamente la suite.
Puede fallar en ambientes más lentos. Puede ocultar problemas de rendimiento o bloqueo.

El objetivo es dar tiempo razonable para que la condición ocurra, sin convertir las fallas en esperas interminables.

13.11 Datos compartidos y ejecución paralela

La inestabilidad no siempre viene de la interfaz. También puede aparecer cuando varias pruebas comparten datos y se ejecutan al mismo tiempo.

Ejemplos:

  • Dos pruebas intentan comprar el último producto en stock.
  • Dos pruebas usan el mismo cupón de un solo uso.
  • Una prueba cancela un turno que otra esperaba reservar.
  • Varias pruebas modifican el mismo usuario.

Para evitarlo, conviene crear datos únicos por ejecución o separar recursos por escenario.

13.12 Ambientes lentos o variables

Un ambiente puede responder de forma diferente según carga, red, servicios externos o recursos disponibles. Si las pruebas dependen de tiempos exactos, serán inestables.

Señales de ambiente variable:

  • Las mismas pruebas tardan tiempos muy distintos.
  • Los servicios externos responden con demoras frecuentes.
  • Las fallas aparecen más en ciertos horarios.
  • La suite falla cuando se ejecuta completa, pero pasa con pruebas aisladas.

En estos casos conviene revisar capacidad del ambiente, aislamiento de datos y dependencias externas.

13.13 Cómo investigar una prueba inestable

Cuando una prueba falla de manera intermitente, no conviene ignorarla ni simplemente repetirla muchas veces. Es mejor investigar la causa.

Pasos útiles:

  • Revisar capturas, videos y registros de la ejecución fallida.
  • Comparar una ejecución fallida con una exitosa.
  • Identificar el punto exacto donde aparece la diferencia.
  • Verificar si la prueba esperaba una condición real o un tiempo fijo.
  • Revisar si los datos eran únicos y estaban preparados.
  • Confirmar si hubo demoras o errores en servicios externos.
  • Reproducir el escenario en el mismo ambiente, si es posible.

El objetivo es convertir una falla intermitente en una causa concreta y corregible.

13.14 Buenas prácticas para reducir inestabilidad

Algunas prácticas ayudan a construir pruebas E2E más estables:

  • Esperar condiciones concretas, no tiempos fijos.
  • Usar datos únicos o aislados por ejecución.
  • Evitar dependencias entre pruebas.
  • Usar selectores estables.
  • Verificar estados finales claros.
  • Controlar servicios externos o usar ambientes de prueba confiables.
  • Registrar evidencias suficientes para diagnosticar fallas.
  • Mantener escenarios cortos y enfocados en un objetivo.

13.15 Ejemplo práctico

Supongamos una prueba que falla porque, después de confirmar una compra, busca inmediatamente el texto "Compra realizada". A veces el mensaje aparece rápido y la prueba pasa. Otras veces el backend tarda más y la prueba falla.

Una versión frágil sería:

Hacer clic en "Confirmar".
Esperar 2 segundos.
Buscar el mensaje "Compra realizada".

Una versión más estable sería:

Hacer clic en "Confirmar".
Esperar hasta que aparezca una confirmación o hasta que el sistema informe un error.
Verificar que la orden aparece en el historial del usuario.

La segunda opción espera señales del flujo y verifica una consecuencia más fuerte.

13.16 Errores comunes

Al tratar sincronización y esperas, conviene evitar estos errores:

  • Agregar pausas fijas cada vez que una prueba falla.
  • Esperar elementos que no prueban que el sistema esté listo.
  • Usar timeouts enormes para ocultar problemas reales.
  • Compartir datos modificables entre pruebas paralelas.
  • Ignorar fallas intermitentes porque "pasan al repetir".
  • No guardar evidencias para investigar fallas.
  • Confundir un problema de ambiente con un defecto sin analizarlo.

13.17 Qué debes recordar de este tema

  • La sincronización coordina la prueba con el estado real de la aplicación.
  • Una prueba inestable pasa y falla sin cambios claros en el comportamiento probado.
  • Las esperas fijas suelen generar pruebas lentas o frágiles.
  • Conviene esperar condiciones concretas y conectadas con el flujo.
  • La visibilidad de un elemento no siempre significa que esté listo para usarse.
  • Los datos compartidos y ambientes variables también causan inestabilidad.
  • Una falla intermitente debe investigarse, no ignorarse.

13.18 Conclusión

La sincronización es uno de los factores que más afecta la confiabilidad de las pruebas End-to-End. Una prueba que avanza antes de tiempo puede fallar aunque el sistema funcione correctamente.

Para reducir inestabilidad, las pruebas deben esperar señales reales del sistema, usar datos controlados, evitar dependencias innecesarias y producir evidencias útiles cuando algo falla.

En el próximo tema veremos selectores, identificadores y elementos confiables para pruebas E2E.