Verifique que se genere una excepción utilizando Mocha / Chai y async / await

Estoy luchando para encontrar la mejor manera de verificar que una promesa sea rechazada en una prueba de Mocha mientras uso async / await.

Aquí hay un ejemplo que funciona, pero no me gusta que should.be.rejectedWith devuelve una promesa que debe devolverse desde la función de prueba para que se evalúe correctamente. El uso de async / await elimina este requisito para los valores de prueba (como lo hago para el resultado de wins() continuación), y creo que es probable que olvide la statement de retorno en algún momento, en cuyo caso la prueba siempre pasará .

 // Always succeeds function wins() { return new Promise(function(resolve, reject) { resolve('Winner'); }); } // Always fails with an error function fails() { return new Promise(function(resolve, reject) { reject('Contrived Error'); }); } it('throws an error', async () => { let r = await wins(); r.should.equal('Winner'); return fails().should.be.rejectedWith('Contrived Error'); }); 

Parece que debería ser posible usar el hecho de que async / await traduce los rechazos a las excepciones y combina eso con el efecto de Chai, pero no he podido determinar la syntax correcta.

Idealmente, esto funcionaría, pero no parece:

 it('throws an error', async () => { let r = await wins(); r.should.equal('Winner'); (await fails()).should.throw(Error); }); 

El problema con este enfoque es que (await fails()).should.throw(Error) no tiene sentido.

await resuelve una Promise . Si la Promise rechaza, arroja el valor rechazado.

Por lo tanto (await fails()).should.throw(Error) nunca puede funcionar: si fails() rechaza, se lanza un error, y .should.throw(Error) nunca se ejecuta.

La opción más idiomática que tienes es usar la propiedad rejectedWith Chai de Chai, como lo has demostrado en tu pregunta.

Aquí hay un ejemplo rápido. No mucho es diferente de lo que has demostrado en tu pregunta; Solo estoy usando funciones async para wins() y fails() y expect lugar de should . Por supuesto, puede usar funciones que devuelvan una Promise y chai.should .

 const chai = require('chai') const expect = chai.expect chai.use(require('chai-as-promised')) // Always succeeds async function wins() { return 'Winner' } // Always fails with an error async function fails() { throw new Error('Contrived Error') } it('wins() returns Winner', async () => { expect(await wins()).to.equal('Winner') }) it('fails() throws Error', async () => { await expect(fails()).to.be.rejectedWith(Error) }) 

Si desea que su prueba de wins() parezca más a su prueba de fails() , puede escribir su prueba de wins() así:

 it('wins() returns Winner', async () => { await expect(wins()).to.eventually.equal('Winner') }) 

La clave a recordar en cualquiera de estos ejemplos es que chai-as-promised promete para sus funciones tales como rejectedWith y eventually.something . Por lo tanto, debe await en el contexto de una función de prueba async o, de lo contrario, las condiciones que fallan aún pasarán:

 async function wins() { return 'Loser' } async function fails() { return 'Winner' } it('wins() returns Winner', async () => { expect(wins()).to.eventually.equal('Winner') }) it('fails() throws Error', async () => { expect(fails()).to.be.rejectedWith(Error) }) 

Si ejecutó las pruebas con el código anterior, obtendría lo siguiente:

 $ npm test > mocha-chai-async@1.0.0 test /home/vsimonian/code/mocha-chai-async > mocha . √ wins() returns Winner (node:13836) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rej ection id: 1): AssertionError: expected 'Loser' to equal 'Winner' (node:13836) [DEP0018] DeprecationWarning: Unhandled promise rejections are dep recated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. √ fails() throws Error (node:13836) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rej ection id: 2): AssertionError: expected promise to be rejected with 'Error' but it was fulfilled with 'Winner' 2 passing (11ms) 

Como puede ver, las afirmaciones chai realmente fallaron, pero fallaron en el contexto de una Promesa que nadie await o catch . Así que Mocha no ve ninguna falla y marca las pruebas como si hubieran pasado, pero Node.js (en el comportamiento que cambiará en el futuro como se indicó anteriormente) imprime los rechazos no manejados al terminal.