Búsqueda de sitios web

javascript - Mocha/Chai expect.to.throw no captura errores lanzados


Estoy teniendo problemas para hacer que expect.to.throw de Chai funcione en una prueba para mi aplicación node.js. La prueba sigue fallando por el error lanzado, pero si envuelvo el caso de prueba en try y catch y hago una aserción sobre el error capturado, funciona.

¿No funciona expect.to.throw como creo que debería o algo?

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();
});

El fracaso:

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.

Respuesta #1

Tienes que pasar una función a expect. Así:

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 manera en que lo estás haciendo, estás pasando a expect el resultado de llamar a model.get('z'). Pero para probar si algo lanza una excepción, tienes que pasar una función a expect, que expect llamará por sí mismo. El método bind usado arriba crea una nueva función que, al ser llamada, invocará model.get con this establecido en el valor de model y el primer argumento establecido en 'z'.

Una buena explicación de bind se puede encontrar aquí.

Respuesta #2

Como dice esta respuesta, también puedes simplemente envolver tu código en una función anónima así:

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

Respuesta #3

Y si ya estás usando ES6/ES2015, entonces también puedes usar una función flecha. Básicamente es lo mismo que usar una función anónima normal, pero más corta.

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

Respuesta #4

Esta pregunta tiene muchos, muchos duplicados, incluidas preguntas que no mencionan la biblioteca de aserción Chai. Aquí están los conceptos básicos recopilados juntos:

La afirmación debe llamar a la función, en lugar de evaluarla inmediatamente.

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

Puedes verificar errores específicos usando cualquier biblioteca de aserción:

Nodo

  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./)

Debería

  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 Esperar

  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./);

Debe manejar las excepciones que 'escapen' de la prueba

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

Esto puede parecer confuso al principio. Como andar en bicicleta, simplemente 'hace clic' para siempre una vez que hace clic.

Respuesta #5

ejemplos del doc... ;)

porque dependes del contexto de this:

  • que se pierde cuando la función es invocada por .throw
  • no hay manera de que pueda saber qué se supone que esto debe ser

tienes que usar una de estas opciones:

  • envolver la llamada al método o función dentro de otra función
  • vincular el contexto

    // 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
    

Artículos relacionados