web-dev-qa-db-fra.com

Test de la promesse rejetée dans Mocha/Chai

J'ai un cours qui refuse une promesse:

Sync.prototype.doCall = function(verb, method, data) {
  var self = this;

  self.client = P.promisifyAll(new Client());

  var res = this.queue.then(function() {
    return self.client.callAsync(verb, method, data)
      .then(function(res) {
        return;
      })
      .catch(function(err) {    
        // This is what gets called in my test    
        return P.reject('Boo');
      });
  });

  this.queue = res.delay(this.options.throttle * 1000);
  return res;
};

Sync.prototype.sendNote = function(data) {
  var self = this;
  return self.doCall('POST', '/Invoice', {
    Invoice: data
  }).then(function(res) {
    return data;
  });
};

Dans mon test:

return expect(s.sendNote(data)).to.eventually.be.rejectedWith('Boo');

Cependant, pendant que le test réussit, l'erreur est renvoyée vers la console.

Rejet non géré Erreur: Boo ...

Avec des erreurs non promises, j’ai utilisé bind to test pour empêcher que l’erreur ne soit renvoyée tant que Chai n’a pas pu boucler et tester:

return expect(s.sendNote.bind(s, data)).to.eventually.be.rejectedWith('Boo');

Cependant, cela ne fonctionne pas avec cela et renvoie:

TypeError: [Function] is not a thenable.

Quelle est la bonne façon de tester cela?

11
cyberwombat

Vous recevez l'erreur car sendNote est rejeté et vous ne la détectez pas.

Essayer:

var callPromise = self.doCall('POST', '/Invoice', {
  Invoice: data
}).then(function(res) {
  return data;
});

callPromise.catch(function(reason) {
  console.info('sendNote failed with reason:', reason);
});

return callPromise;

Il semblerait que vous deviez également déplacer votre capture existante d'un bloc vers l'autre:

var res = this.queue.then(function() {
  return self.client.callAsync(verb, method, data)
    .then(function(res) {
      return;
    });
  }).catch(function(err) {    
    // This is what gets called in my test    
    return P.reject('Boo');
  });
4
rrowland

(Avertissement: C'est une bonne question, même pour les personnes qui n'utilisent pas Bluebird. J'ai posté une réponse similaire ici ; cette réponse fonctionnera pour les personnes qui n'utilisent pas Bluebird.)

avec chai comme promis

Voici comment vous pouvez utiliser chai-as-promise pour tester les cas resolve et reject avec une promesse:

var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);

...

it('resolves as promised', function() {
    return expect(Promise.resolve('woof')).to.eventually.equal('woof');
});

it('rejects as promised', function() {
    return expect(Promise.reject('caw')).to.be.rejectedWith('caw');
});

sans chai comme promis

Vous pouvez accomplir la même chose sans chai comme promis, comme ceci:

it('resolves as promised', function() {
  return Promise.resolve("woof")
    .then(function(m) { expect(m).to.equal('woof'); })
    .catch(function(e) { throw e })  // use error thrown by test suite
           ;
});

it('rejects as promised', function() {
    return Promise.reject("caw")
        .then(function(m) { throw new Error('was not supposed to succeed'); })
        .catch(function(m) { expect(m).to.equal('caw'); })
            ;
});
15
fearless_fool

Personnellement, j'utilise cet idiome:

it('rejects as promised', function() {
    return Promise.reject("caw")
        .then(
          (m) => { assert.fail('was not supposed to succeed'); }
          (m) => { /* some extra tests here */ }
        );
});

C'est l'un des rares cas où then(onFulfilled, onRejected) (2 arguments) est légitime à utiliser.

Si vous enchaînez .then(reject).catch(onRejected) comme suggéré dans d'autres réponses, vous finissez par entrer dans le gestionnaire catch à chaque fois puisqu'il capturera également le rejet produit par le gestionnaire précédent then - ce qui pourrait provoquer des tests à répétition si vous n'êtes pas assez prudent pour vérifier cette éventualité.

6
Sylvain Leroux