Tengo una función recursiva básica, que funciona correctamente cuando se ejecuta. Me gustaría usar los temporizadores falsos de Sinon para probar la función en cada etapa de ejecución.
Sin embargo, parece que los temporizadores falsos solo se aplican a la primera llamada de la función recursiva.
Tengo curiosidad por saber si alguien puede ayudar a descubrir cómo hacer que los temporizadores falsos funcionen todo el tiempo.
Ejemplo:
function wait(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } async function ensureCount(count, { attempt, delay }) { attempt = attempt || 0 console.log('Attempt', attempt) if (attempt === count) { return } await wait(delay) await ensureCount(count, { attempt: attempt + 1, delay }) }Probado así (con la ayuda de este artículo ):
it('retries after a given delay', function() { const clock = sinon.useFakeTimers() const promise = ensureCount(2, { delay: 200 }) clock.tick(200) // Make some assertions. clock.tick(200) // Make some assertions. clock.tick(200) // Make some assertions. return promise })La salida esperada de la consola (que es lo que sucede sin temporizadores falsos):
Attempt 0 Attempt 1 Attempt 2 ✔ retries after a given delay (405ms)La salida real de la consola (que sucede con los temporizadores falsos):
Attempt 0 Attempt 1 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.La pregunta:
¿Hay alguna manera de hacer que los temporizadores falsos se apliquen a cada paso de la llamada recursiva, en lugar de solo al primero?
Resulta que Sinon proporciona una función .tickAsync() para esto que no había visto. (Gracias a este comentario ).
Este código resuelve el problema:
it('retries after a given delay', async () => { const clock = sinon.useFakeTimers() ensureCount(2, { delay: 200 }) await clock.tickAsync(200) // Make some assertions. await clock.tickAsync(200) // Make some assertions. await clock.tickAsync(200) // Make some assertions. clock.restore() })