Promise Rejections
Loading "Error Assertions for Rejected Promises"
Run locally for transcripts
In our
greetByResponse()
function, let's add a check that the given response
is defined. If it's not, we should throw an error, letting the consumer know that they passed an invalid argument to that function.export async function greetByResponse(response: Response) {
if (typeof response === 'undefined') {
throw new Error('Failed to greet the user: no user response provided')
}
const user = await response.json()
return greet(user.firstName)
}
This is a new intention so we need to add a new test for it.
test('throws on greeting user with undefined user response', async () => {
expect(await greetByResponse(undefined)).toBe('???')
})
This is a bit awkward. We expect the
greetByResponse()
function to throw, which means we cannot really await
it. More to that, if the function throws, it won't return anything so we cannot assert the returned value with .toBe()
. We have to assert the thrown error instead.The most straightforward way to catch the error thrown in a promise is to wrap it in a
try/catch
block. Let's do just that:test('throws on greeting user with undefined user response', async () => {
try {
// Wait for the greet function to complete.
await greetByResponse(undefined)
} catch (error) {
// If it fails, assert the error.
expect(error.message).toBe(
'Failed to greet the user: no user response provided',
)
}
})
This does look better, and the test may even pass, but there are still a couple of issues here:
- If the
greetByResponse()
promise resolves, the test will also pass. That would be against our intention. - This test is too verbose. Its setup takes twice as much space on the screen than the actual code and its assertion. Similar to our initial implementation of assertions (when we used inline
try/catch
), the test here focuses too much on how to run instead of what intention we want to validate.
It's time we made it more declarative. Wouldn't it be nice if we had some utility in the
expect()
function that would allow us to assert promise rejections in a more streamlined way? Something like this:await expect(greetByResponse(undefined)).rejects.toThrow(
new Error('Failed to greet the user: no user response provided'),
)
๐จโ๐ผ Well, implementing this new
.rejects.toThrow()
assertion is precisely your task! Bonus points if you consider failing the assertion if the given promise resolves when it shouldn't.