Current section: Testing Asynchronous Code 5 exercises

Handling Promise Rejections


00:00 So the first thing to understand is that this new assertion rejects.toThrow uses a syntax called chaining. In simplified form it looks something like this. So it's an object that returns another object and so forth until we arrive at the method we want to call. I will

00:15 implement this new assertion starting from the type level. So in the setup.ts file we have the assertions interface that represents everything that our expect function returns. So in this interface I will add a new key called rejects that will return an object and that object has

00:31 a property toThrow which is a method that accepts the expected argument. This is the error that we expect our promise to reject with and in turn has a promise as a return value. And this is important because just as promises may take time to resolve they can also take time to reject and it's

00:48 important to wrap this in a promise so we can properly evade that rejection when it's happening. So now when these types are defined I can see that TypeScript is kindly screaming at me that I need to implement them as well. Let's do that. We will add the rejects property here with a toThrow method and let's implement it right here. So the first thing that we need to do is to

01:08 keep in mind that the actual argument that we pass to the expect function is unknown. We don't know what that value is going to be but in the context of rejects.toThrow it must be a promise. So the first thing I will do I will add the check that the actual argument is a promise and if it's not

01:24 I will throw an error that we expect it to receive a promise because we cannot call this assertion on anything else but a promise. Once I do this I will return another promise and in this instance we will return the catch promise. This means that we are not interested when the actual value

01:42 resolves but instead we need a promise when it will reject and here I will compare this error message with which the promise rejected with the expected error coming from the toThrow method and if they are not the same I can just say expected error message to be something but got

01:59 something else. So in this case this is enough for it to work but there is one catch. Since our assertion is focusing on rejections, so we expect rejections to happen, when the actual promise resolves in this implementation it will still pass but that is not correct and what we need to do is

02:17 to add a then handler that will throw an error stating that we are not expecting this promise to resolve. Yes, expected promise to reject. So here we have this implementation that checks the actual argument to be a promise and then returns us another promise that waits for this actual

02:35 promise to reject and then compares the rejection with the error message that we want. Now let's use it in the test. So we have the snippet prepared and now we have this chaining annotated and implemented correctly and we just need to provide an error. I'm going to grab it from the

02:50 source code as it is and pass it right here. So with this let's try running the tests and you can see that we have this test for throwing a rejection when we don't provide the response passing. So even though this is the asynchronicity that we cannot await directly

03:07 because we expect it to fail, we still need to await it. In this case we await the promise returned by the to throw assertion. So then we can always reliably assert on the error that this promise rejected with.