1 00:00:06,480 --> 00:00:09,480 - If you are testing code that involves timers, 2 00:00:09,480 --> 00:00:11,490 your tests are gonna run quite slowly, 3 00:00:11,490 --> 00:00:12,840 and that's a bad thing. 4 00:00:12,840 --> 00:00:14,850 Unit tests are meant to be fast. 5 00:00:14,850 --> 00:00:17,505 The idea is that you can run them quickly and often. 6 00:00:17,505 --> 00:00:19,200 If a test is slow, 7 00:00:19,200 --> 00:00:21,750 you're probably gonna be discouraged from runnin' it, 8 00:00:21,750 --> 00:00:24,930 and then your test and your testing rhythm isn't ideal. 9 00:00:24,930 --> 00:00:27,540 You're meant to be running your tests often and quickly. 10 00:00:27,540 --> 00:00:29,040 So that's a problem. 11 00:00:29,040 --> 00:00:31,719 Having slow unit tests is problematic. 12 00:00:31,719 --> 00:00:34,500 Luckily for us, Jest provides an API, 13 00:00:34,500 --> 00:00:36,540 which allows us to mock timers 14 00:00:36,540 --> 00:00:38,580 you can define a fake timer. 15 00:00:38,580 --> 00:00:43,380 So basically replaces timeouts with a no-op, 16 00:00:43,380 --> 00:00:45,990 so your tests run immediately. 17 00:00:45,990 --> 00:00:47,790 They don't have any delay. 18 00:00:47,790 --> 00:00:49,470 So we're gonna see how to do that in this section. 19 00:00:49,470 --> 00:00:51,480 How do you define fake timers in Jest, 20 00:00:51,480 --> 00:00:53,910 so that code that involves timers 21 00:00:53,910 --> 00:00:56,640 don't actually get delayed when you test them? 22 00:00:56,640 --> 00:01:00,898 So if you wanna follow on it's in the Mocking_Timers folder 23 00:01:00,898 --> 00:01:01,731 in the demo folder. 24 00:01:01,731 --> 00:01:05,937 So if you go into "JsTdd Lesson06: Mocking_Timers", 25 00:01:07,260 --> 00:01:10,620 and if you open that folder in the code editor, 26 00:01:10,620 --> 00:01:11,790 it looks like this. 27 00:01:11,790 --> 00:01:15,090 I've got some code here that is quite slow. 28 00:01:15,090 --> 00:01:18,330 I'm going to test it originally using normal test code. 29 00:01:18,330 --> 00:01:20,820 And we're gonna see that the normal tests are slow 30 00:01:20,820 --> 00:01:22,050 because of the timer. 31 00:01:22,050 --> 00:01:22,883 And then what we'll see 32 00:01:22,883 --> 00:01:25,290 is how to define a fake timer using Jest 33 00:01:25,290 --> 00:01:29,880 We place actual timeouts with a mock, or fake, 34 00:01:29,880 --> 00:01:32,130 so that there isn't any actual delay. 35 00:01:32,130 --> 00:01:36,990 So my unit test will run immediately without any hindrance. 36 00:01:36,990 --> 00:01:37,823 So first of all, 37 00:01:37,823 --> 00:01:39,720 we'll have a look at the code that's quite slow 38 00:01:39,720 --> 00:01:41,400 and see how that works. 39 00:01:41,400 --> 00:01:46,400 So here's the code that uses a timer, countdown function. 40 00:01:46,770 --> 00:01:50,190 I defined it in "operations.js" countdown function. 41 00:01:50,190 --> 00:01:52,860 When you invoke it, you pass in a callback. 42 00:01:52,860 --> 00:01:54,509 And the idea is it'll invoke that callback 43 00:01:54,509 --> 00:01:57,690 after a specified delay. 44 00:01:57,690 --> 00:02:00,180 So inside here uses "setTimeout". 45 00:02:00,180 --> 00:02:02,920 It delays for the specified number of milliseconds 46 00:02:03,858 --> 00:02:05,340 like 4,000 milliseconds. 47 00:02:05,340 --> 00:02:08,490 After that time, it'll invoke this lambda, 48 00:02:08,490 --> 00:02:12,001 and that lambda will call your callback 49 00:02:12,001 --> 00:02:15,250 It'll call you back with this message, you know? 50 00:02:15,250 --> 00:02:18,420 "Four seconds countdown complete." 51 00:02:18,420 --> 00:02:22,320 So when I call this function after four seconds, let's say, 52 00:02:22,320 --> 00:02:24,630 it'll call me back with the result, 53 00:02:24,630 --> 00:02:25,953 this kind of string here. 54 00:02:27,480 --> 00:02:30,180 Okay, so that's fine. 55 00:02:30,180 --> 00:02:31,800 Here is a simple test. 56 00:02:31,800 --> 00:02:35,220 First of all, in my "operations.test.js" 57 00:02:35,220 --> 00:02:37,800 I've got a test that uses a real timer, 58 00:02:37,800 --> 00:02:39,270 or what you'll see is that this test 59 00:02:39,270 --> 00:02:42,363 takes four seconds and a bit to complete. 60 00:02:43,260 --> 00:02:44,940 So have a look what's going on. 61 00:02:44,940 --> 00:02:48,000 It uses a real timer, which is the default behavior. 62 00:02:48,000 --> 00:02:49,761 Remember when you've got timeouts involved, 63 00:02:49,761 --> 00:02:54,761 you need to tell Jest when your test has finished, 64 00:02:55,176 --> 00:02:57,840 And the way you do that in your test 65 00:02:57,840 --> 00:02:59,550 is you have a "done" parameter. 66 00:02:59,550 --> 00:03:01,460 This "done" parameter is a callback into Jest, 67 00:03:01,460 --> 00:03:05,880 and the idea was you call that function when you're done, 68 00:03:05,880 --> 00:03:06,713 okay? 69 00:03:06,713 --> 00:03:08,910 And Jest then knows it can move on to the next test, 70 00:03:08,910 --> 00:03:10,770 so it doesn't get any problems. 71 00:03:10,770 --> 00:03:14,190 So first of all, here, I've got a callback function. 72 00:03:14,190 --> 00:03:16,410 This is a callback function. 73 00:03:16,410 --> 00:03:19,590 that's going to be basically invoked for four seconds. 74 00:03:19,590 --> 00:03:21,780 Here is my call to the countdown function. 75 00:03:21,780 --> 00:03:23,940 I'm calling the countdown function. 76 00:03:23,940 --> 00:03:27,000 I'm giving it my callback function as a parameter. 77 00:03:27,000 --> 00:03:31,680 So this pointer here is a pointer to my function. 78 00:03:31,680 --> 00:03:33,000 After four seconds, 79 00:03:33,000 --> 00:03:35,647 it'll call that function back with this message. 80 00:03:35,647 --> 00:03:37,590 "4 seconds countdown complete." 81 00:03:37,590 --> 00:03:39,655 That message will be passed into here. 82 00:03:39,655 --> 00:03:43,050 So this function will be invoked, but after four seconds. 83 00:03:43,050 --> 00:03:45,210 So my test is gonna take four seconds. 84 00:03:45,210 --> 00:03:48,330 I check that the message is complete and direct, correct? 85 00:03:48,330 --> 00:03:50,767 The message that I get back should be 86 00:03:50,767 --> 00:03:53,430 "4 seconds countdown complete" 87 00:03:53,430 --> 00:03:54,757 That's what I'm expecting to get back. 88 00:03:54,757 --> 00:03:56,880 "4 seconds countdown complete" 89 00:03:56,880 --> 00:03:59,040 Great, and then we're done. 90 00:03:59,040 --> 00:04:01,560 The problem is that it'll take four seconds 91 00:04:01,560 --> 00:04:03,540 for this callback to be invoked. 92 00:04:03,540 --> 00:04:07,980 So it'll take four seconds before Jest can progress. 93 00:04:07,980 --> 00:04:09,660 So if I ran that test, 94 00:04:09,660 --> 00:04:11,190 I could run it like this 95 00:04:11,190 --> 00:04:12,843 usin' real timers. 96 00:04:14,070 --> 00:04:18,150 And the key point to note here is the delay it took. 97 00:04:18,150 --> 00:04:19,680 If you ran this for yourself, 98 00:04:19,680 --> 00:04:22,230 it takes four seconds plus a little bit 99 00:04:22,230 --> 00:04:23,580 to actually complete, 100 00:04:23,580 --> 00:04:24,413 okay? 101 00:04:24,413 --> 00:04:26,460 Because the callback function took four seconds 102 00:04:26,460 --> 00:04:27,900 to be called back, 103 00:04:27,900 --> 00:04:31,590 and that's a problem in production code 104 00:04:31,590 --> 00:04:34,830 because your tests are gonna take forever to complete 105 00:04:34,830 --> 00:04:37,320 if you have real timeouts involved. 106 00:04:37,320 --> 00:04:39,840 So rather than having a real timer, 107 00:04:39,840 --> 00:04:43,080 we can get Jest to mock or fake timers. 108 00:04:43,080 --> 00:04:44,400 This is what you do. 109 00:04:44,400 --> 00:04:47,430 You say to Jest "useFakeTimers" 110 00:04:47,430 --> 00:04:49,500 When you call that function, what Jest does 111 00:04:49,500 --> 00:04:51,544 is it basically mocks these functions 112 00:04:51,544 --> 00:04:53,407 "setTimeoout" 113 00:04:53,407 --> 00:04:54,505 "clearTimeout" 114 00:04:54,505 --> 00:04:55,338 "setInterval" 115 00:04:55,338 --> 00:04:56,180 and "clearInterval" 116 00:04:56,180 --> 00:04:59,430 So if your actual code calls any of these functions, 117 00:04:59,430 --> 00:05:01,770 these functions will be replaced by Jest 118 00:05:01,770 --> 00:05:04,380 with no-op operations 119 00:05:04,380 --> 00:05:05,213 Okay? 120 00:05:05,213 --> 00:05:06,046 So in other words, 121 00:05:06,046 --> 00:05:09,270 if your real code called "setTimeout" or "setInterval" 122 00:05:09,270 --> 00:05:12,450 it's not actually gonna instill a timeout or an interval. 123 00:05:12,450 --> 00:05:13,980 Jest will swallow it, 124 00:05:13,980 --> 00:05:16,560 and the delay is avoided. 125 00:05:16,560 --> 00:05:17,430 At some point, 126 00:05:17,430 --> 00:05:21,720 you might want to reinstate the original timer functions. 127 00:05:21,720 --> 00:05:26,010 So if you use fake timers at the beginnin' of your test, 128 00:05:26,010 --> 00:05:28,478 you might want to restore the original timers afterwards. 129 00:05:28,478 --> 00:05:29,610 Okay? 130 00:05:29,610 --> 00:05:32,917 So this, will reinstate the actual "setTimeout," 131 00:05:32,917 --> 00:05:35,430 "clearTimeout", "setInterval" and "clearInterval" 132 00:05:35,430 --> 00:05:37,770 for the rest of your tests. 133 00:05:37,770 --> 00:05:39,720 So let's see how to do that. 134 00:05:39,720 --> 00:05:44,493 So this is "operationWithFakeTimers.test.js" 135 00:05:46,410 --> 00:05:48,333 In the code. it looks like this. 136 00:05:50,220 --> 00:05:55,050 Okay? So I'm gonna step through the through this example 137 00:05:55,050 --> 00:05:55,883 in a moment, 138 00:05:55,883 --> 00:05:57,630 but I've actually got two tests here. 139 00:05:57,630 --> 00:05:59,070 The first test we're going to look at 140 00:05:59,070 --> 00:06:02,460 is the test that shows how to use fake timers. 141 00:06:02,460 --> 00:06:05,073 So let's have a look at that test function first. 142 00:06:06,000 --> 00:06:07,380 That's what I have here. 143 00:06:07,380 --> 00:06:10,170 So let's step through the code. 144 00:06:10,170 --> 00:06:14,550 So first of all, we tell Jest to use fake timers. 145 00:06:14,550 --> 00:06:16,800 So now whenever we call an operation 146 00:06:16,800 --> 00:06:18,900 that sets a timeout or an interval, 147 00:06:18,900 --> 00:06:21,060 it's not actually gonna take any time. 148 00:06:21,060 --> 00:06:23,043 It's gonna return immediately. 149 00:06:24,090 --> 00:06:26,790 Okay? What I then do, out of interest, 150 00:06:26,790 --> 00:06:30,630 is I spy on the "setTimeout" function, okay? 151 00:06:30,630 --> 00:06:31,710 So you can do that. 152 00:06:31,710 --> 00:06:34,410 "setTimeout" is a global function 153 00:06:34,410 --> 00:06:36,930 It's basically kind of defined on the window object. 154 00:06:36,930 --> 00:06:39,937 So I'm creating a spy that'll say, 155 00:06:39,937 --> 00:06:41,910 "I wanna just verify, you know? 156 00:06:41,910 --> 00:06:43,980 Was that function invoked, 157 00:06:43,980 --> 00:06:46,560 and what parameters was passed into it?" 158 00:06:46,560 --> 00:06:49,140 It's been replaced by Jest, 159 00:06:49,140 --> 00:06:51,120 but my code will still be callin' it. 160 00:06:51,120 --> 00:06:53,280 And I wanna check that it's been called correctly. 161 00:06:53,280 --> 00:06:55,440 So I'm spyin' on this function. 162 00:06:55,440 --> 00:06:57,960 This object here is basically a spy 163 00:06:57,960 --> 00:06:59,640 on the "setTimeout" function, 164 00:06:59,640 --> 00:07:01,590 so I can observe how it's been invoked. 165 00:07:03,360 --> 00:07:04,230 Right? 166 00:07:04,230 --> 00:07:08,370 Okay, now we're ready to actually call our function. 167 00:07:08,370 --> 00:07:10,290 This is the function that I'm testing. 168 00:07:10,290 --> 00:07:14,460 That's the actual countdown function in my real code. 169 00:07:14,460 --> 00:07:16,380 If you remember the countdown function, 170 00:07:16,380 --> 00:07:17,583 it had a callback. 171 00:07:18,420 --> 00:07:21,210 This callback function I've just mocked basically 172 00:07:21,210 --> 00:07:22,860 an empty lambda. 173 00:07:22,860 --> 00:07:25,770 And that function, in my real code, 174 00:07:25,770 --> 00:07:28,020 would've been invoked after four seconds. 175 00:07:28,020 --> 00:07:32,100 Okay? So I've kind of mocked that, and I've passed in four. 176 00:07:32,100 --> 00:07:36,120 So the countdown will set the timeout for four seconds, 177 00:07:36,120 --> 00:07:39,660 but that "setTimeout" has been faked. 178 00:07:39,660 --> 00:07:42,450 So this will not actually take four seconds to complete, 179 00:07:42,450 --> 00:07:44,343 it'll complete immediately. 180 00:07:45,990 --> 00:07:49,096 Right? So that will be fast. 181 00:07:49,096 --> 00:07:51,060 After it's finished, which is, you know? 182 00:07:51,060 --> 00:07:52,650 in a moment's time, 183 00:07:52,650 --> 00:07:57,390 I can verify, "Was the "setTimeout" function invoked 184 00:07:57,390 --> 00:07:59,310 once it should have been?" 185 00:07:59,310 --> 00:08:02,970 When I do a countdown, it should call "setTimeout" 186 00:08:02,970 --> 00:08:06,090 My spy monitors, the "setTimeout" function 187 00:08:06,090 --> 00:08:08,880 Was the "setTimeout" function called once? 188 00:08:08,880 --> 00:08:10,030 Let's make sure it was. 189 00:08:11,310 --> 00:08:15,308 Oh, and also, "What was it called with?" 190 00:08:15,308 --> 00:08:16,590 "setTimeout" 191 00:08:16,590 --> 00:08:20,230 If I just remind you how my countdown function works 192 00:08:22,470 --> 00:08:24,720 That's in here. 193 00:08:24,720 --> 00:08:29,190 My countdown function, it should have called "setTimeout" 194 00:08:29,190 --> 00:08:30,400 with a function 195 00:08:32,370 --> 00:08:35,280 and a value like 4,000. 196 00:08:35,280 --> 00:08:36,780 So we can verify, 197 00:08:36,780 --> 00:08:39,180 we've got a spy that's spying on this function. 198 00:08:39,180 --> 00:08:41,670 We can verify that that function was invoked 199 00:08:41,670 --> 00:08:43,590 with some kind of function 200 00:08:43,590 --> 00:08:46,653 and a value of 4,000 milliseconds, 201 00:08:48,300 --> 00:08:49,590 and that's what I'm doing here. 202 00:08:49,590 --> 00:08:51,667 I'm saying that "setTimeout" function, 203 00:08:51,667 --> 00:08:54,667 "Was it called the last time it was invoked? 204 00:08:54,667 --> 00:08:55,500 "Was it invoked..." 205 00:08:55,500 --> 00:08:59,287 now this syntax here: "expect.any", it's saying, 206 00:08:59,287 --> 00:09:01,860 "Was the "setTimeout" function called 207 00:09:01,860 --> 00:09:04,230 with some kind of function?" 208 00:09:04,230 --> 00:09:06,163 I don't care what function it is. 209 00:09:06,163 --> 00:09:07,897 Some kind of function. 210 00:09:07,897 --> 00:09:10,170 "Was my "setTimeout" function invoked 211 00:09:10,170 --> 00:09:12,117 with some kind of function?" 212 00:09:13,500 --> 00:09:14,493 Yes, it was. 213 00:09:15,450 --> 00:09:18,046 That's verifying that some kind of function 214 00:09:18,046 --> 00:09:21,690 was passed in as the first parameter to "setTimeout" 215 00:09:21,690 --> 00:09:23,700 And by the way, what was the second parameter? 216 00:09:23,700 --> 00:09:25,590 The second parameter should have been 4,000 217 00:09:25,590 --> 00:09:28,050 and verifyin' that this parameter 218 00:09:28,050 --> 00:09:29,430 that was passed into "setTimeout", 219 00:09:29,430 --> 00:09:31,503 the second parameter was 4,000. 220 00:09:32,580 --> 00:09:36,060 Okay? So that was the reason for spying on "setTimeout" 221 00:09:36,060 --> 00:09:38,520 to verify that it was called once, 222 00:09:38,520 --> 00:09:42,240 and to verify that my code called "setTimeout" 223 00:09:42,240 --> 00:09:44,147 with the correct first parameter 224 00:09:44,147 --> 00:09:46,582 and the correct second parameter. 225 00:09:46,582 --> 00:09:51,582 Okay, so I've spied on the "setTimeout" function here. 226 00:09:52,020 --> 00:09:55,740 I'm gonna basically clear the ""setTimeout" function here. 227 00:09:55,740 --> 00:09:57,210 When you clear a spy, 228 00:09:57,210 --> 00:10:00,120 it clears all accrued information by that spy. 229 00:10:00,120 --> 00:10:03,570 It clears the fact that that function's been called once. 230 00:10:03,570 --> 00:10:05,850 It clears the fact that that function was called 231 00:10:05,850 --> 00:10:07,020 with certain parameters. 232 00:10:07,020 --> 00:10:10,830 It resets the spy to have no history, 233 00:10:10,830 --> 00:10:13,893 in case you want to use the spy again in another test. 234 00:10:15,690 --> 00:10:18,390 Okay, so when I run this test here, 235 00:10:18,390 --> 00:10:21,150 the key point is that when I call my countdown, 236 00:10:21,150 --> 00:10:23,223 it doesn't actually wait four seconds to complete. 237 00:10:23,223 --> 00:10:27,540 The "setTimeout" has been faked to return immediately. 238 00:10:27,540 --> 00:10:29,520 So when I run the test... 239 00:10:29,520 --> 00:10:31,470 Oh, and by the way, I forgot to mention this 240 00:10:31,470 --> 00:10:33,750 reinstate real time is at the end. 241 00:10:33,750 --> 00:10:34,583 Okay? 242 00:10:34,583 --> 00:10:35,820 So that will basically put back 243 00:10:35,820 --> 00:10:37,980 the real "setTimeout" function at the end. 244 00:10:37,980 --> 00:10:40,230 When I run my test, 245 00:10:40,230 --> 00:10:42,873 you'll notice that it completes much more quickly. 246 00:10:44,400 --> 00:10:46,470 It didn't wait four seconds to complete. 247 00:10:46,470 --> 00:10:48,873 It basically completed effectively immediately. 248 00:10:49,920 --> 00:10:53,433 Now the key point or one important point, 249 00:10:54,480 --> 00:10:56,550 in my test code 250 00:10:56,550 --> 00:11:01,470 after running each test, I reinstate real timers. 251 00:11:01,470 --> 00:11:03,600 So after that test is finished, 252 00:11:03,600 --> 00:11:07,530 the real "setTimeout" function should be reinstated. 253 00:11:07,530 --> 00:11:10,920 So if I have another test afterwards here 254 00:11:10,920 --> 00:11:12,240 when I run this test, 255 00:11:12,240 --> 00:11:16,050 this test should be using real timers in this case. 256 00:11:16,050 --> 00:11:18,570 So if I ran this test, 257 00:11:18,570 --> 00:11:22,920 that should revert back to give me like a proper delay. 258 00:11:22,920 --> 00:11:26,247 When I call "countdown", it'll call "setTimeout", 259 00:11:27,395 --> 00:11:28,770 it'll be using the real timer. 260 00:11:28,770 --> 00:11:31,800 It reinstates the real timer after each test. 261 00:11:31,800 --> 00:11:34,740 So this should take four seconds 262 00:11:34,740 --> 00:11:37,530 to callback this function here. 263 00:11:37,530 --> 00:11:39,420 Okay, so let's see that then. 264 00:11:39,420 --> 00:11:41,760 When having reinstated real timers, 265 00:11:41,760 --> 00:11:43,504 when I invoke the function, 266 00:11:43,504 --> 00:11:47,400 there should be a real timeout now of four seconds 267 00:11:47,400 --> 00:11:49,000 before this function is invoked. 268 00:11:50,010 --> 00:11:52,380 So let's see if that happens, 269 00:11:52,380 --> 00:11:53,520 and it does. 270 00:11:53,520 --> 00:11:57,690 Okay, so you can mock or fake timers 271 00:11:57,690 --> 00:11:59,460 when they're taking too long, 272 00:11:59,460 --> 00:12:01,050 and you can reinstate them 273 00:12:01,050 --> 00:12:04,020 when you want to experience the full timeout, 274 00:12:04,020 --> 00:12:05,420 if that's important for you.