web-dev-qa-db-fra.com

Mocha / Chai s'attend à ce que les erreurs ne soient pas corrigées

J'ai des problèmes à faire en sorte que expect.to.throw de Chai fonctionne dans un test de mon application node.js. Le test échoue sans cesse sur l'erreur renvoyée, mais si j'emballe le scénario de test pour essayer d'attraper et d'affirmer l'erreur interceptée, cela fonctionne.

Est-ce que expect.to.throw ne fonctionne pas comme je le pense ou non?

it('should throw an error if you try to get an undefined property', function (done) {
  var params = { a: 'test', b: 'test', c: 'test' };
  var model = new TestModel(MOCK_REQUEST, params);

  // neither of these work
  expect(model.get('z')).to.throw('Property does not exist in model schema.');
  expect(model.get('z')).to.throw(new Error('Property does not exist in model schema.'));

  // this works
  try { 
    model.get('z'); 
  }
  catch(err) {
    expect(err).to.eql(new Error('Property does not exist in model schema.'));
  }

  done();
});

L'échec:

19 passing (25ms)
  1 failing

  1) Model Base should throw an error if you try to get an undefined property:
     Error: Property does not exist in model schema.
229
doremi

Vous devez passer une fonction à expect. Comme ça:

expect(model.get.bind(model, 'z')).to.throw('Property does not exist in model schema.');
expect(model.get.bind(model, 'z')).to.throw(new Error('Property does not exist in model schema.'));

De la façon dont vous le faites, vous passez à expect le résultat de l'appel de model.get('z'). Mais pour tester si quelque chose est jeté, vous devez passer une fonction à expect, qui expect s’appellera elle-même. La méthode bind utilisée ci-dessus crée une nouvelle fonction qui, lorsqu'elle est appelée, appelle model.get avec this définie sur la valeur de model et sur le premier argument défini sur 'z'. .

Une bonne explication de bind peut être trouvée ici .

311
Louis

Comme cette réponse dit , vous pouvez aussi simplement envelopper votre code dans une fonction anonyme comme celle-ci:

expect(function(){
    model.get('z');
}).to.throw('Property does not exist in model schema.');
162
twiz

Et si vous utilisez déjà ES6/ES2015, vous pouvez également utiliser une fonction de flèche. C'est fondamentalement la même chose que d'utiliser une fonction anonyme normale mais plus courte.

expect(() => model.get('z')).to.throw('Property does not exist in model schema.');
80
Daniel T.

Cette question a beaucoup, beaucoup de doublons, y compris des questions ne mentionnant pas la bibliothèque d'affirmations Chai. Voici les bases rassemblées ensemble:

L'assertion doit appeler la fonction au lieu de l'évaluation immédiate.

assert.throws(x.y.z);      
   // FAIL.  x.y.z throws an exception, which immediately exits the
   // enclosing block, so assert.throw() not called.
assert.throws(()=>x.y.z);  
   // assert.throw() is called with a function, which only throws
   // when assert.throw executes the function.
assert.throws(function () { x.y.z });   
   // if you cannot use ES6 at work
function badReference() { x.y.z }; assert.throws(badReference);  
   // for the verbose
assert.throws(()=>model.get(z));  
   // the specific example given.
homegrownAssertThrows(model.get, z);
   //  a style common in Python, but not in JavaScript

Vous pouvez vérifier des erreurs spécifiques en utilisant n'importe quelle bibliothèque d'assertions:

Node

  assert.throws(() => x.y.z);
  assert.throws(() => x.y.z, ReferenceError);
  assert.throws(() => x.y.z, ReferenceError, /is not defined/);
  assert.throws(() => x.y.z, /is not defined/);
  assert.doesNotThrow(() => 42);
  assert.throws(() => x.y.z, Error);
  assert.throws(() => model.get.z, /Property does not exist in model schema./)

devrait

  should.throws(() => x.y.z);
  should.throws(() => x.y.z, ReferenceError);
  should.throws(() => x.y.z, ReferenceError, /is not defined/);
  should.throws(() => x.y.z, /is not defined/);
  should.doesNotThrow(() => 42);
  should.throws(() => x.y.z, Error);
  should.throws(() => model.get.z, /Property does not exist in model schema./)

Chai Expect

  expect(() => x.y.z).to.throw();
  expect(() => x.y.z).to.throw(ReferenceError);
  expect(() => x.y.z).to.throw(ReferenceError, /is not defined/);
  expect(() => x.y.z).to.throw(/is not defined/);
  expect(() => 42).not.to.throw();
  expect(() => x.y.z).to.throw(Error);
  expect(() => model.get.z).to.throw(/Property does not exist in model schema./);

Vous devez gérer les exceptions qui "échappent" au test

it('should handle escaped errors', function () {
  try {
    expect(() => x.y.z).not.to.throw(RangeError);
  } catch (err) {
    expect(err).to.be.a(ReferenceError);
  }
});

Cela peut paraître déroutant au début. Comme sur un vélo, il suffit de cliquer pour toujours.

67
Charles Merriam

exemples de doc ...;)

parce que vous vous appuyez sur ce contexte :

  • qui est perdu lorsque la fonction est appelée par . throw
  • il n’ya aucun moyen de savoir ce que cela est supposé être

vous devez utiliser l'une de ces options:

  • encapsule l'appel de méthode ou de fonction à l'intérieur d'une autre fonction
  • lie le contexte

    // wrap the method or function call inside of another function
    expect(function () { cat.meow(); }).to.throw();  // Function expression
    expect(() => cat.meow()).to.throw();             // ES6 arrow function
    
    // bind the context
    expect(cat.meow.bind(cat)).to.throw();           // Bind
    
6

Une autre implémentation possible, plus lourde que la solution .bind (), mais qui permet de préciser le fait que expect () nécessite une fonction qui fournit un contexte this à la fonction couverte, vous pouvez utiliser un call(), par exemple,

expect(function() {model.get.call(model, 'z');}).to.throw('...');

1
SeanOlson