Reputation: 998
I tried to followed the documentation in order to test for the error message using assert.rejects (I do have Node above v10).
But it's always passing, even with a ridiculous message. What am I doing wrong?
it("should fail but it's not",
async ()=> {
let itemId = 'not an id'
assert.rejects(
await ListRepo.checkById(itemId),
{message: 'abracadabra'}
)
}
)
UPDATE: It seems that if I return the assert.rejects, it works. But I still don't know the reason.
Upvotes: 6
Views: 6048
Reputation: 2123
As I write this, everything written above/previously is correct, but much of it is needlessly complicated. It is correct that you must return a promise, so that mocha itself has something to wait for, otherwise it returns immediately (before your promise can resolve or reject). The missing piece is that manually waiting for a promise is rarely what you actually want to do here.
This simplest pattern is hinted at by @caub in a comment--await the promise returned by assert.rejects
. Specifically:
it("should fail but it's not",
async ()=> {
let itemId = 'not an id'
await assert.rejects(
ListRepo.checkById(itemId),
{message: 'abracadabra'}
)
}
)
There are three key things here:
async
.await
the assert.rejects
call inside the (async) test function. This automatically makes the test function return Promise<void>
, which is exactly what you want. This puts the important part right at the point of the assert call, and compared to manually returning/handling a promise, makes it easier to copy/paste the call elsewhere and makes it easier to assert multiple rejections in one test.await
what you're passing into the rejects
call. You should be passing in a promise--not an await
ed value.Upvotes: 12
Reputation: 41
What nicholaswmin said is correct, but there's a "rest of the owl" moment here that I'd like to clear-up.
If your desire is: "I want to assert reject", i.e. "I want to make sure this code rejects in the right way," the pattern is a bit complicated.
First off, write in return fxnWhichReturnsPromise()
. The test will fail if your function is rejecting, and you want the inverse of that. You have to use the two-argument signature of .then()
, which looks like: .then(onFulfillCallback, onRejectCallback)
, since if you split it into .then
& .catch
, failing in the .then
-block will be caught by the subsequent .catch
-block, and what should be a failing test (it did not reject) will be a passing one.
In practice, altogether it looks something like this:
it('rejects when given foobar', () => {
return fxnThatShouldReject(foobar)
.then(
(val) => { assert.fail(`Should have rejected, returned with ${val} instead`)
,
(err) => { assert.equal(err.message, "Rejection reason I was expecting") }
)
})
The reason the assertion library does not have a built-in assertion handler for this is because being able to "hold-up" asynchronous execution in the test suite is really a test-runner capability. assert.throws()
is synchronous, by contrast.
Upvotes: 1