The problem with this approach is that (await fails()).should.throw(Error)
doesn't make sense.
await
resolves a Promise
. If the Promise
rejects, it throws the rejected value.
So (await fails()).should.throw(Error)
can never work: if fails()
rejects, an error is thrown, and .should.throw(Error)
is never executed.
The most idiomatic option you have is to use Chai's rejectedWith
property, as you have shown in your question.
Here's a quick example. Not much is different from what you've demonstrated in your question; I'm just using async
functions for wins()
and fails()
and expect
instead of should
. Of course, you can use functions that return a Promise
and chai.should
just fine.
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)
})
If you like want your wins()
test to resemble your fails()
test more closely, you can write your wins()
test like so:
it('wins() returns Winner', async () => {
await expect(wins()).to.eventually.equal('Winner')
})
The key thing to remember in either of these examples is that chai-as-promised
returns promises for its functions such as rejectedWith
and eventually.something
. Therefore you must await
them in the context of an async
test function, or else failing conditions will still pass:
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)
})
If you ran the tests with the code above, you'd get the following:
$ npm test
> [email protected] test /home/adaline/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)
As you can see, the chai assertions actually failed, but they were failed in the context of a Promise that no one ever await
ed or catch
ed. So Mocha sees no failure and marks the tests as though they passed, but Node.js (in behaviour that will change in the future as noted above) prints the unhandled rejections to the terminal.