1 00:00:06,510 --> 00:00:08,700 - In this section, we're going to take a closer look 2 00:00:08,700 --> 00:00:10,500 at how to mock timers, 3 00:00:10,500 --> 00:00:12,150 a couple of useful techniques, 4 00:00:12,150 --> 00:00:15,600 which allow you to artificially move the timeline, 5 00:00:15,600 --> 00:00:18,360 when you are setting up fake timers. 6 00:00:18,360 --> 00:00:20,700 So, imagine you set up a fake timer. 7 00:00:20,700 --> 00:00:22,770 You said just use fake timers. 8 00:00:22,770 --> 00:00:24,040 That means when you call set timeout 9 00:00:24,040 --> 00:00:28,980 or clear time out or set interval or clear interval 10 00:00:28,980 --> 00:00:31,590 just won't call the real functions. 11 00:00:31,590 --> 00:00:34,680 It'll effectively call mock functions instead, 12 00:00:34,680 --> 00:00:35,790 but that's okay. 13 00:00:35,790 --> 00:00:37,890 But you can call this function as well 14 00:00:37,890 --> 00:00:40,890 which artificially advances all timers 15 00:00:40,890 --> 00:00:42,720 as if they'd completed. 16 00:00:42,720 --> 00:00:43,710 So if you'd set a timeout 17 00:00:43,710 --> 00:00:46,590 in your code of a minute, when you call this function 18 00:00:46,590 --> 00:00:49,650 it'll simulate the elapsed time of a minute. 19 00:00:49,650 --> 00:00:51,810 It'll say, okay, the time has elapsed 20 00:00:51,810 --> 00:00:55,020 and that any callbacks, which you, you were hoping to call 21 00:00:55,020 --> 00:00:57,240 you know, after a minute will be invoked 22 00:00:57,240 --> 00:00:59,010 but without actually having to wait for that time. 23 00:00:59,010 --> 00:01:01,590 So it automatically moves the timeline to 24 00:01:01,590 --> 00:01:04,983 complete any timers which are currently pending. 25 00:01:06,240 --> 00:01:08,940 Closely related and more powerful, 26 00:01:08,940 --> 00:01:13,020 you can advance timers by a certain number of milliseconds. 27 00:01:13,020 --> 00:01:15,840 So imagine you set up a call back to happen 28 00:01:15,840 --> 00:01:18,540 after 10 seconds and another call back to happen 29 00:01:18,540 --> 00:01:21,960 after 20 seconds and another call back after 30 seconds. 30 00:01:21,960 --> 00:01:26,370 You can artificially move the timeline by 10 seconds 31 00:01:26,370 --> 00:01:28,350 like moving the timeline 32 00:01:28,350 --> 00:01:31,200 in a video when you're watching it on TV. 33 00:01:31,200 --> 00:01:34,170 So you can add artificially advance the timer by 10 seconds 34 00:01:34,170 --> 00:01:36,780 and see if the first callback has been invoked. 35 00:01:36,780 --> 00:01:40,530 And then you can artificially move the timer to 20 seconds 36 00:01:40,530 --> 00:01:42,690 and see if the second call back has been invoked 37 00:01:42,690 --> 00:01:44,610 without actually having to wait for 10 seconds 38 00:01:44,610 --> 00:01:47,790 to it is just like fast forwarding, in a movie. 39 00:01:47,790 --> 00:01:51,030 And you can control how far you want to move the timeline 40 00:01:51,030 --> 00:01:54,000 and see what happens when you do that. 41 00:01:54,000 --> 00:01:55,980 So we're gonna have a look at examples of both 42 00:01:55,980 --> 00:01:57,960 of these functions in this section. 43 00:01:57,960 --> 00:01:59,790 If you wanna have a look for yourself, 44 00:01:59,790 --> 00:02:03,873 mock in timers techniques as the folder, here it is. 45 00:02:03,873 --> 00:02:06,693 If you open that in the code editor, 46 00:02:08,130 --> 00:02:09,390 this is what it looks like. 47 00:02:09,390 --> 00:02:11,490 So I have an operation. 48 00:02:11,490 --> 00:02:12,900 This is actually the same operation. 49 00:02:12,900 --> 00:02:16,584 As in the previous section, I have a countdown function. 50 00:02:16,584 --> 00:02:20,520 When I call it, I pass in a callback function. 51 00:02:20,520 --> 00:02:23,490 It'll invoke that function after the specified number 52 00:02:23,490 --> 00:02:27,210 of seconds in, in real implementation, it sets the time out. 53 00:02:27,210 --> 00:02:28,980 Obviously I'm gonna to fake that time out. 54 00:02:28,980 --> 00:02:30,766 So it doesn't actually have to, I don't actually 55 00:02:30,766 --> 00:02:34,320 have to wait that long, but in the real world, it would wait 56 00:02:34,320 --> 00:02:35,250 that many seconds. 57 00:02:35,250 --> 00:02:38,670 And then eventually call me back with a message. 58 00:02:38,670 --> 00:02:43,080 You know, four seconds countdown complete in a real code. 59 00:02:43,080 --> 00:02:44,790 It would take four seconds. 60 00:02:44,790 --> 00:02:47,553 For example, for that to come back. 61 00:02:49,230 --> 00:02:50,400 Because I'm impatient, 62 00:02:50,400 --> 00:02:52,320 and I can't be bothered to wait four seconds. 63 00:02:52,320 --> 00:02:54,723 I'm going to fake timers, have a look. 64 00:02:55,740 --> 00:02:56,733 There's my code. 65 00:02:57,570 --> 00:02:59,820 This is the scenario that we're going to, 66 00:02:59,820 --> 00:03:01,260 we're going to use. 67 00:03:01,260 --> 00:03:05,285 I'm going to, in my test, I'm going to call that function 68 00:03:05,285 --> 00:03:08,580 specify a call back and a delay. 69 00:03:08,580 --> 00:03:09,810 I'll verify 70 00:03:09,810 --> 00:03:12,030 that the call back function hasn't been invoked yet. 71 00:03:12,030 --> 00:03:15,270 Obviously when, when you first call countdown 72 00:03:15,270 --> 00:03:17,190 it hasn't invoked the call back yet. 73 00:03:17,190 --> 00:03:18,510 In fact, it never would 74 00:03:18,510 --> 00:03:21,180 because there isn't really a timer anymore. 75 00:03:21,180 --> 00:03:24,480 So what I can do is I can artificially run the timer 76 00:03:24,480 --> 00:03:25,860 to completion as if to say 77 00:03:25,860 --> 00:03:29,250 well, a real timer would be waiting four seconds. 78 00:03:29,250 --> 00:03:31,530 I'm going to artificially run the timer 79 00:03:31,530 --> 00:03:34,950 to completion as if the timer had actually completed 80 00:03:34,950 --> 00:03:36,720 but without time to wait for it. 81 00:03:36,720 --> 00:03:38,040 And then I can say, well, you know 82 00:03:38,040 --> 00:03:40,350 after that time after that's happened 83 00:03:40,350 --> 00:03:42,840 then this call back should have been invoked. 84 00:03:42,840 --> 00:03:47,070 So having artificially moved the timeline forward I can 85 00:03:47,070 --> 00:03:48,960 to completion, I can then say 86 00:03:48,960 --> 00:03:52,050 has the call back function now been invoked? 87 00:03:52,050 --> 00:03:54,720 Okay. So you can move time without time to wait for it. 88 00:03:54,720 --> 00:03:55,650 It's great. 89 00:03:55,650 --> 00:03:57,960 Makes the test run more quickly. 90 00:03:57,960 --> 00:03:59,760 So here's my test. 91 00:03:59,760 --> 00:04:03,390 This is the first example where I'm going to run all timers. 92 00:04:03,390 --> 00:04:06,930 First of all, establish an artificial fake timer. 93 00:04:06,930 --> 00:04:08,910 I don't want to call the real set timeout 94 00:04:08,910 --> 00:04:10,140 that would take too long. 95 00:04:10,140 --> 00:04:13,470 I'm impatient, unit tests are meant to be quick. 96 00:04:13,470 --> 00:04:15,570 So let's fake the timers. 97 00:04:15,570 --> 00:04:19,200 What I then do is I, I call and countdown. 98 00:04:19,200 --> 00:04:21,360 I specify a dummy callback. 99 00:04:21,360 --> 00:04:24,180 I'm not really interested in the callback function itself. 100 00:04:24,180 --> 00:04:26,280 So I've got a dummy callback function 101 00:04:26,280 --> 00:04:30,060 a mock function and a timer before. 102 00:04:30,060 --> 00:04:33,990 Okay. So there's a set timeout call a call 103 00:04:33,990 --> 00:04:38,670 set timeout with a parameter of four seconds. 104 00:04:38,670 --> 00:04:40,830 The set timeout function has been mocked. 105 00:04:40,830 --> 00:04:45,720 So initially my call back should not have been called. 106 00:04:45,720 --> 00:04:46,770 Okay then. 107 00:04:46,770 --> 00:04:47,603 And here's the key point. 108 00:04:47,603 --> 00:04:49,620 I ran all timers to completion. 109 00:04:49,620 --> 00:04:53,610 In other words, I say to my, you know, faked set timer 110 00:04:53,610 --> 00:04:55,950 you know, you thought you were waiting for seconds 111 00:04:55,950 --> 00:04:57,150 it's finished. 112 00:04:57,150 --> 00:05:01,260 So at that point, my countdown function should 113 00:05:01,260 --> 00:05:03,780 invoke the call back, okay. 114 00:05:03,780 --> 00:05:06,720 Having kind of moved the clock forward so 115 00:05:06,720 --> 00:05:09,840 that the timer has finished after that's happened. 116 00:05:09,840 --> 00:05:11,970 My countdown function should have invoked the 117 00:05:11,970 --> 00:05:14,013 the call back once. 118 00:05:15,480 --> 00:05:19,230 So this gives us the benefit of not having to wait 119 00:05:19,230 --> 00:05:20,760 for the timer to actually complete. 120 00:05:20,760 --> 00:05:23,790 We can artificially tell it, pretend that you've completed 121 00:05:23,790 --> 00:05:27,060 and then see what happens afterwards. 122 00:05:27,060 --> 00:05:29,820 When I run that test, it works. 123 00:05:29,820 --> 00:05:32,190 And the other key point is that it didn't actually 124 00:05:32,190 --> 00:05:33,810 take four seconds. 125 00:05:33,810 --> 00:05:36,660 It completed effectively, immediately. 126 00:05:36,660 --> 00:05:40,710 I think the timer, so set timer, wasn't really being called 127 00:05:40,710 --> 00:05:44,910 and then basically simulated the completion of all timeout. 128 00:05:44,910 --> 00:05:47,730 And after that point, I can verify my callback function 129 00:05:47,730 --> 00:05:50,670 should have been invoked after the time it was complete. 130 00:05:50,670 --> 00:05:53,820 So semantically, it behaves as if the timeout had actually 131 00:05:53,820 --> 00:05:56,430 finished, and my callback function is called, 132 00:05:56,430 --> 00:05:58,500 but without having to actually wait 133 00:05:58,500 --> 00:06:00,100 for that to happen in real time. 134 00:06:01,397 --> 00:06:02,250 Good, isn't it. 135 00:06:02,250 --> 00:06:03,442 I like this. 136 00:06:03,442 --> 00:06:05,070 You can take it a step further. 137 00:06:05,070 --> 00:06:08,610 And instead of running all timers to completion immediately 138 00:06:08,610 --> 00:06:11,190 you can move the timeline in intervals. 139 00:06:11,190 --> 00:06:12,630 So have a look at this. 140 00:06:12,630 --> 00:06:14,400 First of all, I'm using fake timers. 141 00:06:14,400 --> 00:06:16,560 Avoid real timers. 142 00:06:16,560 --> 00:06:18,930 I'm actually gonna call countdown three times. 143 00:06:18,930 --> 00:06:20,730 I'm gonna give it three callback functions 144 00:06:20,730 --> 00:06:23,370 three dummy callback functions. 145 00:06:23,370 --> 00:06:25,980 The first dummy should be invoked after 10 seconds 146 00:06:25,980 --> 00:06:30,210 of elapsed time, either real or invented the second callback 147 00:06:30,210 --> 00:06:33,870 after 20 seconds and the third callback after 30 seconds. 148 00:06:33,870 --> 00:06:36,750 Now there isn't any actual timeout involved 149 00:06:36,750 --> 00:06:38,370 because I faked it. 150 00:06:38,370 --> 00:06:41,580 I have to artificially move the timeline forward. 151 00:06:41,580 --> 00:06:44,310 Before I've done any artificial movement of time, 152 00:06:44,310 --> 00:06:47,250 those callbacks have not yet been invoked. 153 00:06:47,250 --> 00:06:50,550 I then artificially move the timeline forward 154 00:06:50,550 --> 00:06:52,680 as if 10 seconds had elapsed. 155 00:06:52,680 --> 00:06:56,100 You specified milliseconds here, 10,000 milliseconds 156 00:06:56,100 --> 00:07:00,030 all being well after 10 seconds of elapsed time 157 00:07:00,030 --> 00:07:02,640 this first callback should have been invoked. 158 00:07:02,640 --> 00:07:04,890 So has it been, let's verify 159 00:07:04,890 --> 00:07:07,200 that the first callback has not been invoked 160 00:07:07,200 --> 00:07:10,830 because effectively 10 seconds have elapsed. 161 00:07:10,830 --> 00:07:13,380 The other callbacks should not have been invoked yet 162 00:07:13,380 --> 00:07:16,710 because this callback was waiting for 20 seconds 163 00:07:16,710 --> 00:07:19,590 and this callback was waiting for 30 seconds. 164 00:07:19,590 --> 00:07:23,070 And so far I've just moved the clock forward by 10 seconds. 165 00:07:23,070 --> 00:07:26,010 So the first function would've been called back 166 00:07:26,010 --> 00:07:26,843 but the other se- 167 00:07:26,843 --> 00:07:29,340 the other two haven't yet been called back. 168 00:07:29,340 --> 00:07:31,650 I've actually got a full implementation. 169 00:07:31,650 --> 00:07:35,103 If I show you the full code in the code editor for this. 170 00:07:37,080 --> 00:07:37,913 Let's have a look, 171 00:07:37,913 --> 00:07:42,120 operation with fake timers dot test dot JS. 172 00:07:42,120 --> 00:07:47,120 So as you can see, I've set up my three dummy callbacks. 173 00:07:47,253 --> 00:07:51,120 Okay. And then I say, you know, call back the first dummy 174 00:07:51,120 --> 00:07:54,060 after 10 seconds, call back the second dummy call back 175 00:07:54,060 --> 00:07:57,130 after 20 and the third dummy call back after 30 176 00:07:58,530 --> 00:08:00,030 before time has moved on. 177 00:08:00,030 --> 00:08:02,820 Basically the time is now still, still sitting at time zero, 178 00:08:02,820 --> 00:08:06,930 no callbacks have yet been evoked after 10 seconds 179 00:08:06,930 --> 00:08:09,300 of artificial time movement. 180 00:08:09,300 --> 00:08:11,340 We're now on the ten second timer. 181 00:08:11,340 --> 00:08:13,493 The first callback should have been invoked once, 182 00:08:13,493 --> 00:08:16,560 the second callback hasn't been called yet 183 00:08:16,560 --> 00:08:18,990 because it needed 20 seconds. 184 00:08:18,990 --> 00:08:21,720 The third callback needed 30 seconds. 185 00:08:21,720 --> 00:08:24,120 Let's move the clock on another 10 seconds. 186 00:08:24,120 --> 00:08:27,780 So that's 20 seconds now cumulatively. 187 00:08:27,780 --> 00:08:31,170 So after 20 seconds, okay, the first callback has still 188 00:08:31,170 --> 00:08:36,090 been invoked 10 seconds ago in our imaginary time span. 189 00:08:36,090 --> 00:08:38,764 The second callback has not been invoked 190 00:08:38,764 --> 00:08:40,950 but the third callback hasn't been invoked yet 191 00:08:40,950 --> 00:08:43,340 because it needed 30 seconds of a lapse time. 192 00:08:43,340 --> 00:08:45,000 So you can kind of see how this works. 193 00:08:45,000 --> 00:08:48,990 Every time you call advanced timer by, it moves the timer 194 00:08:48,990 --> 00:08:51,600 forwards by a specified amount. 195 00:08:51,600 --> 00:08:53,970 And you can see what should have happened 196 00:08:53,970 --> 00:08:56,460 after that interval or that interval, 197 00:08:56,460 --> 00:08:59,010 or after 30 seconds after another 10, 198 00:08:59,010 --> 00:09:01,500 then all callbacks should now have been evoked 199 00:09:01,500 --> 00:09:03,810 effectively 30 seconds have now relapsed. 200 00:09:03,810 --> 00:09:06,480 And that means all the functions should have been evoked 201 00:09:06,480 --> 00:09:09,360 after that amount of time in total. 202 00:09:09,360 --> 00:09:12,360 So you get a chance to experience the, you know 203 00:09:12,360 --> 00:09:15,810 the actual flow of time and what happens in time. 204 00:09:15,810 --> 00:09:18,480 But without time to wait for 10 actual seconds 205 00:09:18,480 --> 00:09:21,960 you can fast forward to see what should happen 206 00:09:21,960 --> 00:09:25,923 at that moment in time simulated here. 207 00:09:26,910 --> 00:09:29,250 So we just need to run the test. 208 00:09:29,250 --> 00:09:34,250 So I've run the test and it works, hooray, and again 209 00:09:34,260 --> 00:09:36,720 the key point to note is because I've 210 00:09:36,720 --> 00:09:40,470 I'm using fake timers in a real code base. 211 00:09:40,470 --> 00:09:43,973 It would take 30 seconds for those callbacks to complete 212 00:09:43,973 --> 00:09:48,000 because I'm artificially advanced in time, like 213 00:09:48,000 --> 00:09:51,780 in a blink of an eye, the test completes really quickly. 214 00:09:51,780 --> 00:09:53,930 And that's what you want with unit testing.