tardis.js

Viajando en el tiempo de forma transparente

Para un proyecto tuve la necesidad de una herramienta que me permitiera cambiar el “momento actual” de una aplicación JavaScript. Les presento a tardis.js.

tardis.js

Esta es una pequeña, pequeñísima librería (es más grande por dentro) que nos permite alterar el momento actual del objeto Date del navegador. Esto ocurre de forma transparente a cualquier librería que lo utilice, de forma que es integrable con cualquier otra librería.

La utilización es extremadamente simple: una vez cargada la librería tenemos a nuestra disposición el objeto global tardis:

En el ejemplo anterior, lo siguiente está ocurriendo:

  1. Obtenemos la fecha actual, como normalmente lo haríamos. En este caso utilizamos new Date(), pero Date.now() también podría servirnos.
  2. Le indicamos a tardis.js que queremos movernos 24 horas hacia el futuro. La multiplicación es para lograr el número equivalente en milisegundos, que pasaremos como argumento a la función travelToFuture.
  3. Ahora obtenemos la fecha actual nuevamente, para ver que el navegador reporta creer que estamos en el día siguiente. No fue necesario cambiar la fecha del sistema ni cerrar el navegador. El objeto devuelto es un objeto Date, exactamente igual que en el paso 1.
  4. Le indicamos a tardis.js que queremos desplazarnos una hora hacia el pasado. Igual que en el paso 2, realizamos la conversión a milisegundos y lo pasamos como argumento, esta vez a la función travelToPast.
  5. Ahora obtenemos otra vez la fecha actual: nos encontramos con que la fecha reportada tiene ambos desplazamientos acumulados: estamos exactamente 23 horas en el futuro.
  6. Finalmente, cancelamos todo nuestro movimiento y le pedimos a tadis.js que devuelva la fecha atual real, utilizando el método restoreTime, sin argumentos.
  7. Obtenemos la fecha nuevamente para verificar y nos encontramos que hemos vuelto a nuestro punto de partida.

Situaciones en la que puede ser útil

Existen aplicaciones que en cierto punto de su lógica, usan la fecha actual para determinar el valor de salida. Imaginen un caso en donde la aplicación muestra la fecha y hora de la última actualización, y por simplicidad, no hace más que obtener un objeto new Date() y mostrar sus dígitos en pantalla.

Esa simplicidad se torna en nuestra contra cuando queremos hacer unit testing o testing automatizado de nuestra aplicación, porque tenemos una variable que no podemos controlar: el momento actual. Esto significa que si nuestro test valida que esa fecha y hora diga “11:00 AM”, hay un sólo minuto del día en el cual ese test va a pasar la prueba.

Una forma de solucionar esto es inyectar los objetos que le permiten a la aplicación obtener la fecha. Es decir, usar un objeto Date que obtiene por parámetro y en el entorno de tests, inyectar un objeto que podemos controlar para tener un horario fijo. Si bien esto es una buena prácica, esto sacrifica completamente la simplicidad de la solución, y algo tan simple como obtener la fecha actual se debe convertir en utilizar objetos que cumplan con cierta interfaz y que sean inyectados antes de la existencia de esa parte de nuestra aplicación.

tardis.js hace eso mismo, pero reemplazando el objeto window.Date del navegador temporalmente, y generando un método wrapper alrededor de él, de forma que la aplicación puede suponer que window.Date siempre está ahí y va a tener el valor que espera, y tardis.js trabaja tras las cortinas para devolver un Date con los parámetros apropiados.

Cualquier test que dependa de la fecha actual es un buen candidato para estas pruebas. Más ejemplos:

  • “Fecha de última actualización” para contenido offline
  • Timestamp de mensajes recibidos, en una aplicación de mensajería
  • Servicios que se disparan cada cierto tiempo (checkeos cada 1 minuto, cada 1 hora, etc.) NOTA: si se están usando setTimeout o setInterval para estos casos, quizá convenga una librería más completa, como sinon.js fake timers.
  • Relojes

¿Por qué no usar sinon.js?

Hay casos particulares en donde fakeTimers de sinon.js interfiere con el funcionamiento normal de nuestra aplicación. En el caso particular que yo encontré, utilizar sinon.js fake timers afectaba el ciclo natural del runLoop de EmberJS, y el framework de EmberJS testing. Llegaban a ser incompatibles al punto en donde los tests automáticos ya no podían ejecutarse con normalidad, y desarrollé tardis.js para hacer una solución más liviana al problema que yo tenía.

Para el resto de las situaciones, totalmente recomiendo sinon.js fake timers. Es sumamente completo y muy fácil de controlar.

Feedback

El proyecto se encuentra disponible en su repositorio de GitHub, y está abierto a propuestas, ideas, críticas, reporte de bugs y mejoras. Pueden enviar esos a través de pull requests o desde la sección de issues del mismo repositorio.

También estaría feliz de escuchar feedback si es que quieren contactarme por los canales habituales, @AlphaTwi en Twitter siendo la forma más simple.