Web App Testing & Tools

Testing Timeouts

Miško Hevery

Miško Hevery

Qwik Creator (Previously Angular)
Web App Testing & Tools

Check out a free preview of the full Web App Testing & Tools course

The "Testing Timeouts" Lesson is part of the full, Web App Testing & Tools course featured in this preview video. Here's what you'd learn in this lesson:

Miško adds a test to verify the asynchronous call times out after a set delay. Testing delays can slow down the test runner, so the test is then refactored so the delay can be resolved immediately. The final code is located on the lesson-3 branch


Transcript from the "Testing Timeouts" Lesson

>> So now we have a next to-do. And in this test, it says we should time out after x seconds. So let's implement this first. And I'm gonna show you what kind of issues we will have with the implementation. So, when you are talking to a fetch over here, if you wanna time out, you will need to have some kind of a delay.

So let's create a delay function. And Autopilot is amazing at writing delay, perfect, okay. I think that's correct, right? Yeah, that's right. So now this gives me a promise that allows me to delay a particular thing. And what we can do now is we can say, race.await. No, sorry, not race, promise.race.

Promise.race. And, I see. So, okay. It's unknown because, right, these are different types. So we're gonna cheat here and we're gonna say, then. So the thing is, we're refactoring it so that we return a timeout value. So, we have a delay, and after a delay, we say return, let's say response equals timeout.

Otherwise, we do our normal stuff, right? And now we have to say, then, we get a response. And in the response, we copy this piece of code right here, which basically says return response.json. And we can go and just return it. And they delete this code right here.

So now we have code that will wait up to 5,000 milliseconds, it's a race between two promises, right? Either this promise tries, to actually fetch the data, or we have a delay and we will resolve in 5,000 milliseconds saying like, hey, there's a timeout. Actually, let's make this timeout a little shorter, 4,000, because the 5,000 is also what we test.

So, let's make a new test. And somebody was asking me, do I copy the tests or do I like to be dry? So, I actually like to copy the tests, because it makes it easier to kind of figure out what is going on. So let's just copy this test over, remove this expect, and we'll do expect here.

And it's an async. Okay, so now we have the same exact test, but what we are gonna do is we're not we're not going to resolve the the response, instead we're just gonna wait. And if I get my test going, notice that we have a test that's failing, and it's saying, hey, I expected to have a response, but instead I got a timeout.

So actually this is what we wanna do. We wanna assert that we have a timeout, right? So instead of response, we have a timeout like this. And now you'll see that this test passes, hopefully, if I did this right, it's passing because it's doing exactly what I wanted, right?

I didn't provide a response, and it, four seconds later, provided a timeout response, which is exactly what we wanted. However, as you can imagine, you don't wanna have a test like this, how do I hide the background? Okay, you don't want to have a test like this inside of your repo because it takes four seconds to execute, and if you have hundreds and hundreds of them, this would be a problem.

So the question then becomes, how do we simulate this? How do we solve this? And I'm gonna ask the audience.
>> Timeout should be an argument.
>> [CROSSTALK] That's right, so we need to now pass in the delay in here, right? So, we can essentially continue the same exact process, where we say, const delay mock is going to be a function that is going to be getting a mock promise.

So the argument of the function is gonna be a number. And it's gonna return a promise. And now we have to take this mock and pass it in to our API. And then inside of our API, we will do the same exact thing. We will say, we have a delay, and the delay will be a function that takes a millisecond, which is a number, which produces a promise.

And yeah, we can have a default value in here and we can also have a default value here. Oops, fetch. Actually, is that allowed? Can you have the fetch name to be the same as this fetch? I don't actually know. We'll find out in a second. And so, now, instead of just calling delay, we will call this .delay.

So that we control, we, again, get to the other side of things. And if I go back to my test, My test is now timing out, because the same way as we are mocking the other response, we have to mock this one, right? So, we assert that we're gonna get called in a correct way and then we do the limax to have been called with 4000.

And then we say, delay mock mock results the first result value that we got we actually resolve it and we now assert that you have the right output, let's see. Yeah, that's not allowed, my fault on that. Names cannot match, so I can't do this. This delay is not a function.

Right. So now the issue is that we have broken our previous test. So our previous test now also wants to delay mock, so we now have to pass a mock in here. We can just do under a function like this. I think this is just gonna complain about the type.

Let's go back. Okay, so now we are passing again. So the same thing that we have done previously, we're repeating over here, right? We are sandwiching ourselves in. So you can see that this is how we can control not just the external APIs, but also we get to control the time, right?

Because I get to decide when individual promises resolve, and so I can change the order in which the promises resolve, I can pretend the time is moving forward by whatever amount I want, etc. And so, this is a way to get a full control over the stuff.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now