web-dev-qa-db-fra.com

NodeJS UnhandledPromiseRejectionWarning

Je teste donc un composant qui repose sur un émetteur d'événements. Pour ce faire, j'ai trouvé une solution utilisant Promises avec Mocha + Chai:

it('should transition with the correct event', (done) => {
  const cFSM = new CharacterFSM({}, emitter, transitions);
  let timeout = null;
  let resolved = false;
  new Promise((resolve, reject) => {
    emitter.once('action', resolve);
    emitter.emit('done', {});
    timeout = setTimeout(() => {
    if (!resolved) {
      reject('Timedout!');
    }
    clearTimeout(timeout);
  }, 100);
}).then(((state) => {
      resolved = true;
      assert(state.action === 'DONE', 'should change state');
      done();
    }))
    .catch((error) => {
      assert.isNotOk(error,'Promise error');
      done();
    });
  });
});

Sur la console, un message 'UnhandledPromiseRejectionWarning' s'affiche même si la fonction de rejet est appelée car elle affiche instantanément le message 'AssertionError: erreur de promesse'.

(noeud: 25754) UnhandledPromiseRejectionWarning: Promesse non gérée rejet (id de rejet: 2): AssertionError: erreur de promesse: attendu {Object (message, showDiff, ...)} être faux 1) devrait passer avec le bon événement

Et puis, après 2 secondes je reçois 

Erreur: dépassement du délai d'attente de 2000 ms. Assurez-vous que le rappel done () est être appelé dans ce test.

Ce qui est encore plus étrange depuis l'exécution du rappel de capture (je pense que pour une raison quelconque, l'échec de l'assertion a empêché le reste de l'exécution). 

Maintenant, chose amusante, si je commente le assert.isNotOk(error...), le test se déroule sans avertissement dans la console. Il échoue encore dans le sens où il exécute la capture.
Mais encore, je ne peux pas comprendre ces erreurs avec la promesse. Est-ce que quelqu'un peut m'éclairer?

97
Jzop

Le problème est causé par ceci:

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

Si l'assertion échoue, une erreur sera générée. Cette erreur fera que done() ne sera jamais appelé, car le code a été erroné avant. C'est ce qui cause le délai d'attente.

La "rejet de promesse non gérée" est également causée par l'assertion manquée, car si une erreur est renvoyée dans un gestionnaire catch(), et qu'il n'y a pas de gestionnaire catch() suivant, l'erreur sera avalée (comme expliqué dans cet article ). L’avertissement UnhandledPromiseRejectionWarning vous avertit de ce fait.

En général, si vous souhaitez tester du code basé sur des promesses dans Mocha, vous devez vous fier au fait que Mocha lui-même peut déjà gérer les promesses. Vous ne devriez pas utiliser done(), mais plutôt renvoyer une promesse de votre test. Mocha sera alors attraper les erreurs lui-même.

Comme ça:

it('should transition with the correct event', () => {
  ...
  return new Promise((resolve, reject) => {
    ...
  }).then((state) => {
    assert(state.action === 'DONE', 'should change state');
  })
  .catch((error) => {
    assert.isNotOk(error,'Promise error');
  });
});
124
robertklep

Les bibliothèques d'assertions dans Mocha fonctionnent en générant une erreur si l'assertion n'était pas correcte. Le lancement d'une erreur entraîne le rejet d'une promesse, même si elle est lancée dans la fonction exécuteur fournie à la méthode catch.

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

Dans le code ci-dessus, error objected est évalué à true de sorte que la bibliothèque d'assertions génère une erreur ... qui n'est jamais interceptée. En raison de l'erreur, la méthode done n'est jamais appelée. Le rappel done de Mocha accepte ces erreurs, vous pouvez donc simplement mettre fin à toutes les chaînes de promesses dans Mocha avec .then(done,done). Cela garantit que la méthode done est toujours appelée et que l'erreur serait rapportée de la même manière que lorsque Mocha intercepte l'erreur de l'assertion dans un code synchrone.

it('should transition with the correct event', (done) => {
  const cFSM = new CharacterFSM({}, emitter, transitions);
  let timeout = null;
  let resolved = false;
  new Promise((resolve, reject) => {
    emitter.once('action', resolve);
    emitter.emit('done', {});
    timeout = setTimeout(() => {
      if (!resolved) {
        reject('Timedout!');
      }
      clearTimeout(timeout);
    }, 100);
  }).then(((state) => {
    resolved = true;
    assert(state.action === 'DONE', 'should change state');
  })).then(done,done);
});

Je donne crédit à cet article à l’idée d’utiliser .then (terminé, fait) lors du test des promesses dans Mocha.

8
Matthew Orlando

J'ai eu cette erreur en écrasant avec sinon.

Le correctif consiste à utiliser le package npm sinon-comme-promise lors de la résolution ou du rejet de promesses avec des stubs.

Au lieu de ...

sinon.stub(Database, 'connect').returns(Promise.reject( Error('oops') ))

Utilisation ...

require('sinon-as-promised');
sinon.stub(Database, 'connect').rejects(Error('oops'));

Il existe également une méthode resolves (notez le s à la fin).

Voir http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejections

8
danday74

Pour ceux qui recherchent l'erreur/avertissement UnhandledPromiseRejectionWarning en dehors d'un environnement de test, cela pourrait être probablement du fait que personne dans le code ne s'occupe de l'erreur éventuelle dans une promesse:

Par exemple, ce code affichera l'avertissement signalé dans cette question:

new Promise((resolve, reject) => {
  return reject('Error reason!');
});

(node:XXXX) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error reason!

et l'ajout de .catch() ou le traitement de l'erreur devrait résoudre l'avertissement/l'erreur

new Promise((resolve, reject) => {
  return reject('Error reason!');
}).catch(() => { /* do whatever you want here */ });

Ou en utilisant le second paramètre de la fonction then

new Promise((resolve, reject) => {
  return reject('Error reason!');
}).then(null, () => { /* do whatever you want here */ });
4
gsalgadotoledo

Voici mon expérience de prise avec E7 asynchrone/wait :

Si vous avez un async helperFunction() appelé depuis votre test ... (une explication avec le mot clé ES7 async, je veux dire)

→ assurez-vous que vous appelez cela comme await helperFunction(whateverParams) (ouais, bien sûr, une fois que vous savez ...)

Et pour que cela fonctionne (pour éviter, "wait est un mot réservé"), votre fonction de test doit avoir un marqueur async externe:

it('my test', async () => { ...
1
Frank Nocke

J'ai fait face à ce problème:

(node: 1131004) UnhandledPromiseRejectionWarning: Rejet de promesse non gérée (id ID de jection: 1): TypeError: res.json n'est pas une fonction DeprecationWarning: les rejets de promesses non gérées sont obsolètes . À l'avenir, les refus de promesse qui ne sont pas traités mettront fin à Node.j s processus avec un code de sortie non nul.

C'était mon erreur, je remplaçais l'objet res dans then(function(res), alors j'ai changé res en conséquence et maintenant cela fonctionne.

Faux

module.exports.update = function(req, res){
        return Services.User.update(req.body)
                .then(function(res){//issue was here, res overwrite
                    return res.json(res);
                }, function(error){
                    return res.json({error:error.message});
                }).catch(function () {
                   console.log("Promise Rejected");
              });

Correction

module.exports.update = function(req, res){
        return Services.User.update(req.body)
                .then(function(result){//res replaced with result
                    return res.json(result);
                }, function(error){
                    return res.json({error:error.message});
                }).catch(function () {
                   console.log("Promise Rejected");
              });

Code de service:

function update(data){
   var id = new require('mongodb').ObjectID(data._id);
        userData = {
                    name:data.name,
                    email:data.email,
                    phone: data.phone
                };
 return collection.findAndModify(
          {_id:id}, // query
          [['_id','asc']],  // sort order
          {$set: userData}, // replacement
          { "new": true }
          ).then(function(doc) {
                if(!doc)
                    throw new Error('Record not updated.');
                return doc.value;   
          });
    }

module.exports = {
        update:update
}
0

J'ai résolu ce problème après la désinstallation de Webpack (problème js).

Sudo uninstall webpack
0
Mr Fun