web-dev-qa-db-fra.com

Comment puis-je échouer à un test en Jest quand un rejet de promesse non capturé se produit?

Je travaille sur l'ajout d'une couverture de test à un projet de nœud sur lequel je travaille à l'aide de Jest. Le code que je teste génère des erreurs dans les promesses, ce qui entraîne la consignation d'un message UnhandledPromiseRejectionWarning dans la console.

Lors de la rédaction des tests, je peux facilement identifier ces problèmes et les résoudre, mais ces avertissements ne permettent pas réellement à Jest de marquer les tests comme ayant échoué, de sorte que notre CI ne les détecte pas. J'ai cherché des suggestions et n'ai pas trouvé grand chose.

J'ai trouvé dans la documentation de Node que vous pouvez intercepter ces avertissements et les gérer ...

process.on('unhandledRejection', (error) => {
  throw error; // Or whatever you like...
});

Il semble donc assez simple d'ajouter ce code à mes cas tests. Après tout, une Error jetée dans le test devrait provoque l'échec du test ...

describe('...', () => {
  it('...', () => {
    process.on('uncaughtRejection', (error) => {
      throw error;
    });

    // the rest of my test goes here
  });
});

Malheureusement, le comportement que je constate est que l'erreur provoque est renvoyée, mais Jest ne l'attrape pas et échoue le test. Au lieu de cela, Jest se bloque avec cette erreur et les tests ne continuent pas à s'exécuter. Ce n'est pas vraiment souhaitable, et semble être un comportement incorrect.

Le lancement d'une erreur en dehors du gestionnaire uncaughtRejection fonctionne comme prévu: Jest enregistre l'erreur renvoyée et échoue le test, mais ne plante pas. (c’est-à-dire que l’observateur de tests surveille et exécute les tests)

6
Jesse Dunlap

La façon dont j'ai abordé cette question est étroitement liée à la manière dont j'écris mes fonctions - en gros, toute fonction qui utilise des promesses devrait rendre une promesse. Cela permet à tous les appels de code de cette fonction de gérer les erreurs de capture de la manière qui lui semble la plus appropriée. Notez que ceci est mon approche et je ne vais pas prétendre que c'est la seule façon de faire les choses.

Par exemple ... Imaginez que je teste cette fonction:

const myFunction = () => {
    return doSomethingWithAPromise()
        .then(() => {
            console.log('no problems!');
            return true;
        });
};

Le test ressemblera à ceci:

describe('...', () => {
    it('...', () => {
        return myFunction()
            .then((value) => {
                expect(value).toBe(true);
            });
    });
});

Ce qui fonctionne très bien. Maintenant que se passe-t-il si la promesse est rejetée? Dans mon test, la promesse rejetée est renvoyée à Jest (parce que je retourne le résultat de mon appel de fonction) et Jest peut en faire rapport.

Si, au lieu de cela, votre fonction ne renvoie pas de promesse, vous devrez peut-être faire quelque chose comme ceci:

const myOtherFunction = () => {
    doSomethingWithAPromise()
        .then(() => {
            console.log('no problems!');
            return true;
        })
        .catch((err) => {
             // throw the caught error here
             throw err;
        });
};

Contrairement à l'exemple ci-dessus, Jest ne dispose d'aucun moyen (direct) de traiter une promesse rejetée, car vous ne la renvoyez pas à Jest. Une façon d'éviter ceci pourrait être de s'assurer qu'il existe une catch dans la fonction permettant de récupérer l'erreur, mais je ne l'ai pas essayée et je ne suis pas sûre qu'elle soit plus fiable.

1
Kryten