2017-10-12 15 views
1

J'essaie de comprendre le test asynchrone de Jest.Test d'une promesse en utilisant setTimeout avec Jest

Mon module a une fonction qui accepte un booléen et renvoie une promesse de valeur. La fonction d'exécution appelle setTimeout et, dans le rappel de délai dépassé, la promesse résout ou rejette en fonction du booléen initialement fourni. Le code ressemble à ceci:

const withPromises = (passes) => new Promise((resolve, reject) => { 
    const act =() => { 
    console.log(`in the timout callback, passed ${passes}`) 
     if(passes) resolve('something') 
     else reject(new Error('nothing')) 
    } 

    console.log('in the promise definition') 

    setTimeout(act, 50) 
}) 

export default { withPromises } 

Je voudrais tester cela en utilisant Jest. Je suppose que je dois utiliser les minuteries simulés Jest fournit, donc mon script de test ressemble un peu à ceci:

import { withPromises } from './request_something' 

jest.useFakeTimers() 

describe('using a promise and mock timers',() => { 
    afterAll(() => { 
     jest.runAllTimers() 
    }) 


    test('gets a value, if conditions favor',() => { 
     expect.assertions(1) 
     return withPromises(true) 
      .then(resolved => { 
       expect(resolved).toBe('something') 
      }) 
    }) 
}) 

J'obtiens l'erreur suivante/test a échoué, si j'appelle jest.runAllTimers()

Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. 

Pouvez-vous expliquer où je me trompe et ce que je pourrais faire pour obtenir un test de passage que la promesse se résout comme prévu?

Répondre

3

L'appel à jest.useFakeTimers() se moque de chaque fonction de temporisateur avec celui que vous doit contrôle. Au lieu que la minuterie fonctionne automatiquement, vous l'avancez manuellement. La fonction jest.runTimersToTime(msToRun) l'avance de msToRun millisecondes. Il est très fréquent que vous souhaitiez avancer rapidement jusqu'à ce que chaque temporisateur se soit écoulé et il serait fastidieux de calculer le temps nécessaire pour que tous les temporisateurs se terminent, donc Jest fournit jest.runAllTimers(), qui prétend que le temps a passé.

Le problème dans votre test est que vous n'appelez jest.runAllTimers() dans le test, mais vous l'appelez dans le crochet afterAll, qui est appelé après les essais ont terminé. Pendant votre test, la minuterie reste à zéro, votre callback n'est jamais appelé et Jest l'abandonne après un intervalle prédéfini (par défaut: 5s) pour éviter d'être bloqué avec un test potentiellement interminable. Seulement après que le test a expiré, vous appelez jest.runAllTimers(), à quel point il ne fait rien, puisque tous les tests sont déjà terminés.

Ce que vous devez faire est de lancer la promesse et ensuite faire avancer le temporisateur.

describe('using a promise and mock timers',() => { 
    test('gets a value, if conditions favor',() => { 
     expect.assertions(1) 
     // Keep a reference to the pending promise. 
     const pendingPromise = withPromises(true) 
      .then(resolved => { 
       expect(resolved).toBe('something') 
      }) 
     // Activate the timer (pretend the specified time has elapsed). 
     jest.runAllTimers() 
     // Return the promise, so Jest waits for its completion and fails the 
     // test when the promise is rejected. 
     return pendingPromise 
    }) 
}) 
+0

Cela fonctionne! Merci beaucoup pour l'explication et l'explication et l'exemple de code. –