1 00:00:06,557 --> 00:00:09,090 - In the last lesson, we saw how you can mock 2 00:00:09,090 --> 00:00:11,790 an existing function in jest. 3 00:00:11,790 --> 00:00:16,290 You call jest.fn, and it gives you back a mock function. 4 00:00:16,290 --> 00:00:19,770 If you want to, you can mock all the functions in module, 5 00:00:19,770 --> 00:00:22,770 as we've seen already, you call jest.mock. 6 00:00:22,770 --> 00:00:24,480 You specify the name of your module, 7 00:00:24,480 --> 00:00:26,070 the name of the file, 8 00:00:26,070 --> 00:00:29,280 and it will mock every function in that file. 9 00:00:29,280 --> 00:00:33,060 So effectively, it replaces every function in this module 10 00:00:33,060 --> 00:00:34,530 with a mock version. 11 00:00:34,530 --> 00:00:37,620 It avoids calling the original function. 12 00:00:37,620 --> 00:00:41,490 Now, sometimes, rather than replacing a function, 13 00:00:41,490 --> 00:00:44,700 you want to spy on, or intercept calls 14 00:00:44,700 --> 00:00:46,260 to an existing function. 15 00:00:46,260 --> 00:00:49,530 So to do that, you can call jest.spyOn 16 00:00:49,530 --> 00:00:51,780 So import a model that contains functions 17 00:00:51,780 --> 00:00:56,280 upon which you want to spy, call jest.spyOn, 18 00:00:56,280 --> 00:00:58,890 specify the module that you just imported, 19 00:00:58,890 --> 00:01:02,070 and specify the function that you want to intercept. 20 00:01:02,070 --> 00:01:06,060 This would give you back a spy, which intercepts calls 21 00:01:06,060 --> 00:01:08,253 to the function that you've just specified. 22 00:01:09,240 --> 00:01:12,450 So the spy here detects 23 00:01:12,450 --> 00:01:16,230 and records information about calls to that function. 24 00:01:16,230 --> 00:01:19,140 But the original function is still called as normal. 25 00:01:19,140 --> 00:01:21,240 So there is a different philosophy here, 26 00:01:21,240 --> 00:01:25,620 when you say mock, or jest.fn, 27 00:01:25,620 --> 00:01:28,680 its replacing a call to divisional function, 28 00:01:28,680 --> 00:01:31,020 whereas when you say jest.spyOn, 29 00:01:31,020 --> 00:01:34,200 the ultimate function will still be invoked, but you get 30 00:01:34,200 --> 00:01:36,840 to record information about how it was invoked, 31 00:01:36,840 --> 00:01:38,403 it's interceptor or spy. 32 00:01:39,720 --> 00:01:44,580 So we gonna look at an example in the Mocking_SpyOn folder. 33 00:01:44,580 --> 00:01:48,273 So if you want to follow on, this is where it's located. 34 00:01:49,680 --> 00:01:51,390 If you're gonna do less than six, 35 00:01:51,390 --> 00:01:54,870 we're in the Mocking_SpyOn folder, here it is. 36 00:01:54,870 --> 00:01:57,390 And if you open that up in a code editor, 37 00:01:57,390 --> 00:01:58,380 this is what it looks like. 38 00:01:58,380 --> 00:02:00,210 As I'm gonna show you in a moment, 39 00:02:00,210 --> 00:02:04,620 I have high level operations in operations.js, 40 00:02:04,620 --> 00:02:07,740 and functions in there called lower level functions 41 00:02:07,740 --> 00:02:10,230 in their messaging.js. 42 00:02:10,230 --> 00:02:12,210 And when I call a function on here, 43 00:02:12,210 --> 00:02:15,870 I'm going to spy on how it calls functions in here. 44 00:02:15,870 --> 00:02:19,080 So let's see the scenario pictorially. 45 00:02:19,080 --> 00:02:22,590 So in my high level module, operations.js, 46 00:02:22,590 --> 00:02:24,240 I'm gonna have high level functions. 47 00:02:24,240 --> 00:02:25,710 I mean, they're not that high level, 48 00:02:25,710 --> 00:02:28,500 add, subtract, multiply, and divide. 49 00:02:28,500 --> 00:02:30,780 When I call the add function, or the subtract, 50 00:02:30,780 --> 00:02:32,760 or the multiply or the divide, 51 00:02:32,760 --> 00:02:35,820 those functions will invoke lower level functions 52 00:02:35,820 --> 00:02:38,580 in messaging.js to output 53 00:02:38,580 --> 00:02:41,190 or to generate informational messages, 54 00:02:41,190 --> 00:02:43,833 or warning messages, or error messages. 55 00:02:44,790 --> 00:02:47,910 So the functions on the module 56 00:02:47,910 --> 00:02:52,680 on the left will call functions on the module on the right. 57 00:02:52,680 --> 00:02:57,300 When I call the add function in my code, for example, 58 00:02:57,300 --> 00:03:00,567 it will call one of these functions over here. 59 00:03:00,567 --> 00:03:03,060 And what you can do is you can define a spy 60 00:03:03,060 --> 00:03:05,073 to intercept those calls. 61 00:03:05,940 --> 00:03:08,010 So the spies kind of sit in the middle. 62 00:03:08,010 --> 00:03:10,500 They intercept calls to the info method, 63 00:03:10,500 --> 00:03:12,480 or the warn method, or the error method. 64 00:03:12,480 --> 00:03:13,890 And the motivation for doing this 65 00:03:13,890 --> 00:03:16,890 is to see was the info method called? 66 00:03:16,890 --> 00:03:18,900 Was it called with the right parameter? 67 00:03:18,900 --> 00:03:20,970 Was the warn method not called? 68 00:03:20,970 --> 00:03:24,540 You can check, or you can verify how these methods here 69 00:03:24,540 --> 00:03:27,150 interact with these methods here to make sure 70 00:03:27,150 --> 00:03:29,643 that these methods get called as expected. 71 00:03:31,350 --> 00:03:34,380 So these are my low level messages. 72 00:03:34,380 --> 00:03:35,340 These are the messages 73 00:03:35,340 --> 00:03:38,250 on the right hand side, messaging.js. 74 00:03:38,250 --> 00:03:40,200 These are the messages that I'm going to spy on, 75 00:03:40,200 --> 00:03:42,660 or the functions I'm gonna spy on. 76 00:03:42,660 --> 00:03:45,700 I have an info function, it takes a message 77 00:03:46,650 --> 00:03:48,660 it builds up a string. 78 00:03:48,660 --> 00:03:50,130 It gets the current time stamp. 79 00:03:50,130 --> 00:03:54,990 Oh, by the way, I've got helper module called Take datetime, 80 00:03:54,990 --> 00:03:58,170 which basically returns the current date and time. 81 00:03:58,170 --> 00:04:00,360 You can have a look at that if you like, 82 00:04:00,360 --> 00:04:02,763 it's here, datetime.js. 83 00:04:05,220 --> 00:04:07,110 Okay, so it has a now string function, 84 00:04:07,110 --> 00:04:08,580 it just returns the current date 85 00:04:08,580 --> 00:04:12,120 and time as an ISO standard string, 86 00:04:12,120 --> 00:04:14,760 a standard string format, year, year, year, year, 87 00:04:14,760 --> 00:04:16,860 month, month, day, day, hours, minutes, 88 00:04:16,860 --> 00:04:18,870 and seconds and milliseconds. 89 00:04:18,870 --> 00:04:21,990 Anyway, so that's basically what that function does. 90 00:04:21,990 --> 00:04:25,200 So that's not particularly significant. 91 00:04:25,200 --> 00:04:29,970 So when we call the info function with a message, 92 00:04:29,970 --> 00:04:31,350 it will return the time stamp 93 00:04:31,350 --> 00:04:36,150 and info followed by the message, and warning followed 94 00:04:36,150 --> 00:04:39,390 by the message, and error followed by the message. 95 00:04:39,390 --> 00:04:41,220 So these are the low level functions, 96 00:04:41,220 --> 00:04:43,110 but I'm going to call for my high level. 97 00:04:43,110 --> 00:04:46,860 I want to spy on how these functions are invoked. 98 00:04:46,860 --> 00:04:49,710 So my high level code looks like this. 99 00:04:49,710 --> 00:04:52,140 I import those lower level functions 100 00:04:52,140 --> 00:04:53,460 that I just showed you. 101 00:04:53,460 --> 00:04:57,480 The add function, it calls message.info 102 00:04:57,480 --> 00:04:59,640 to generate an informational message, 103 00:04:59,640 --> 00:05:02,550 you know, within the add function with parameter A 104 00:05:02,550 --> 00:05:05,190 and parameter B, that should be turned a string, 105 00:05:05,190 --> 00:05:09,390 say an info, which we display on console. 106 00:05:09,390 --> 00:05:11,670 And the subtract method also displays 107 00:05:11,670 --> 00:05:13,530 an informational message. 108 00:05:13,530 --> 00:05:16,860 And the multiply does as well. 109 00:05:16,860 --> 00:05:19,260 The divide method is a bit more interesting 110 00:05:19,260 --> 00:05:21,120 because if you divide by zero, 111 00:05:21,120 --> 00:05:22,860 that's potentially problematic. 112 00:05:22,860 --> 00:05:27,860 So if the denominator is zero, I output a warning message. 113 00:05:27,990 --> 00:05:31,740 So this function will either call the warn method 114 00:05:31,740 --> 00:05:33,372 or the info method. 115 00:05:33,372 --> 00:05:37,500 If the denominator is zero, it'll gimme a warning. 116 00:05:37,500 --> 00:05:39,150 If the denominator isn't zero, 117 00:05:39,150 --> 00:05:41,040 it'll just open an information message. 118 00:05:41,040 --> 00:05:44,610 So that's relatively interesting, when I call this function, 119 00:05:44,610 --> 00:05:49,020 I can spy on whether it called that one, or that one, 120 00:05:49,020 --> 00:05:50,970 and that's what I'm going to do in my tests. 121 00:05:50,970 --> 00:05:52,560 So just before we look at the tests, 122 00:05:52,560 --> 00:05:54,030 I'll just show you the actual code, 123 00:05:54,030 --> 00:05:56,610 just to confirm it's as I've explained. 124 00:05:56,610 --> 00:06:00,603 So just to reiterate then my low level functions here. 125 00:06:01,470 --> 00:06:04,260 My function that returns an informational message, 126 00:06:04,260 --> 00:06:06,540 my function that returns a warning message, 127 00:06:06,540 --> 00:06:08,880 and my function that returns an error message. 128 00:06:08,880 --> 00:06:11,220 Those are the functions I'm gonna spy upon. 129 00:06:11,220 --> 00:06:12,240 I call those functions 130 00:06:12,240 --> 00:06:15,423 for my high level code in operations.js. 131 00:06:16,830 --> 00:06:19,500 Okay, and that code as I just explained as well. 132 00:06:19,500 --> 00:06:21,960 It either caused message info, 133 00:06:21,960 --> 00:06:25,290 or message one, or potentially message error 134 00:06:25,290 --> 00:06:27,693 if I had some problematic situation. 135 00:06:28,620 --> 00:06:31,350 So now we're gonna have a look at the test code 136 00:06:31,350 --> 00:06:35,010 to see how when I call this function, how can I spy 137 00:06:35,010 --> 00:06:38,340 on how it interacts with these lower level functions? 138 00:06:38,340 --> 00:06:41,370 How can I ensure in my test that when I call this function, 139 00:06:41,370 --> 00:06:43,200 it has in fact called 140 00:06:43,200 --> 00:06:46,320 the correct lower level method properly. 141 00:06:46,320 --> 00:06:48,090 So let's have a look at the test code. 142 00:06:48,090 --> 00:06:50,640 Here's my first step. 143 00:06:50,640 --> 00:06:53,640 I'm going to set up a spy on those three functions. 144 00:06:53,640 --> 00:06:57,930 So at the top of my test harness, I spy, well, 145 00:06:57,930 --> 00:07:01,830 first of all, I import the messaging module, messaging JS. 146 00:07:01,830 --> 00:07:03,837 I spy on the info function, 147 00:07:03,837 --> 00:07:05,970 and the warn function, and the error function. 148 00:07:05,970 --> 00:07:08,310 Those are the actual names of the functions, 149 00:07:08,310 --> 00:07:09,990 and you get back a spy. 150 00:07:09,990 --> 00:07:12,750 So remember what's going on here. 151 00:07:12,750 --> 00:07:17,750 We had the warn, the function, and the error function. 152 00:07:17,940 --> 00:07:20,490 Oh, and the info function, I forgot about that one. 153 00:07:20,490 --> 00:07:22,290 Those are the three functions we've got. 154 00:07:22,290 --> 00:07:24,240 And what I'm setting up here, 155 00:07:24,240 --> 00:07:26,670 what I'm setting up here, here, and here, 156 00:07:26,670 --> 00:07:29,463 I'm setting up a spy that kind of sit here. 157 00:07:31,560 --> 00:07:35,220 And it will monitor and detect any calls that are made 158 00:07:35,220 --> 00:07:38,850 to the info, or the warn, or the error function. 159 00:07:38,850 --> 00:07:42,720 These spies here are these objects here. 160 00:07:42,720 --> 00:07:46,500 These are my spies which will detect calls 161 00:07:46,500 --> 00:07:48,990 to those individual functions. 162 00:07:48,990 --> 00:07:52,680 When you set up a spy, it accumulates information. 163 00:07:52,680 --> 00:07:55,260 Every time you call the SpyOn function, 164 00:07:55,260 --> 00:07:57,097 it has an internal counter to say, 165 00:07:57,097 --> 00:07:59,640 "Oh, you've called that function again." 166 00:07:59,640 --> 00:08:02,190 So what I'm gonna do, at the end of each test, 167 00:08:02,190 --> 00:08:04,290 I'm going to clear all mocks. 168 00:08:04,290 --> 00:08:07,020 When you say, "Clear all mocks," it basically wipes out 169 00:08:07,020 --> 00:08:10,620 any accumulated information in these spies. 170 00:08:10,620 --> 00:08:13,260 Like, it sets the call count back to zero. 171 00:08:13,260 --> 00:08:15,990 And that's important, when you're doing unit testing, 172 00:08:15,990 --> 00:08:17,550 it's important that you kind of start 173 00:08:17,550 --> 00:08:19,263 with a blank canvas every time. 174 00:08:20,580 --> 00:08:23,670 So just to point to those notes, 175 00:08:23,670 --> 00:08:26,160 we first of all imported the messaging module. 176 00:08:26,160 --> 00:08:27,210 Obviously, we need to do that 177 00:08:27,210 --> 00:08:29,040 if we're gonna call those functions. 178 00:08:29,040 --> 00:08:31,620 Define spies on those functions. 179 00:08:31,620 --> 00:08:36,450 And after each test, clear all information accrued 180 00:08:36,450 --> 00:08:37,380 by those spies. 181 00:08:37,380 --> 00:08:41,190 So basically, each spy, reset the count to zero 182 00:08:41,190 --> 00:08:44,670 in each case ready for the next test to take place. 183 00:08:44,670 --> 00:08:47,583 So that code sits at the top of my test harness. 184 00:08:48,930 --> 00:08:50,460 If you wanted to take a look, 185 00:08:50,460 --> 00:08:52,667 here it is operations.testjs. 186 00:08:54,480 --> 00:08:56,820 This is the code where I set up my spies. 187 00:08:56,820 --> 00:09:01,203 I could have called it info spy, warn spy, error spy. 188 00:09:02,610 --> 00:09:05,040 Oh, and there, after each test, 189 00:09:05,040 --> 00:09:08,640 we'll clear all accrued information ready to go again. 190 00:09:08,640 --> 00:09:10,290 I've actually got two tests. 191 00:09:10,290 --> 00:09:13,890 I've got one test there, one test there, 192 00:09:13,890 --> 00:09:15,690 let's have a look at those tests now. 193 00:09:15,690 --> 00:09:18,600 So the first test, I'm gonna call the divide function. 194 00:09:18,600 --> 00:09:21,270 So well, as I just discussed, probably about a couple 195 00:09:21,270 --> 00:09:24,453 of minutes ago, you know, when you call the divide function, 196 00:09:26,190 --> 00:09:28,200 what the divide function does, 197 00:09:28,200 --> 00:09:30,900 it depends on whether the numerator, sorry, 198 00:09:30,900 --> 00:09:34,830 the denominator was zero or non-zero. 199 00:09:34,830 --> 00:09:37,230 If the denominator was non-zero, 200 00:09:37,230 --> 00:09:41,940 then the divide function will say, "That's great, 201 00:09:41,940 --> 00:09:43,620 thank you very much for that." 202 00:09:43,620 --> 00:09:47,010 And it caused the info function to get back 203 00:09:47,010 --> 00:09:50,940 an informational message, "I've got a spy sitting here 204 00:09:50,940 --> 00:09:52,497 that'll detect that call." 205 00:09:53,490 --> 00:09:56,580 However, if I passed in the denominator of zero, 206 00:09:56,580 --> 00:09:58,950 then instead of calling the info function, 207 00:09:58,950 --> 00:10:00,960 it'll call the warn function. 208 00:10:00,960 --> 00:10:03,540 And I've got a spy that detects that as well. 209 00:10:03,540 --> 00:10:06,060 Oh, and also, just for good measure, 210 00:10:06,060 --> 00:10:09,750 I've also got a spy that's ready to intercept any calls 211 00:10:09,750 --> 00:10:12,510 to the error function if those took place. 212 00:10:12,510 --> 00:10:14,940 So what I do when I call the divide function, 213 00:10:14,940 --> 00:10:18,210 the divide function will proceed as normal, it will call... 214 00:10:18,210 --> 00:10:20,547 Well, if I pass in a denominator of 20, 215 00:10:20,547 --> 00:10:24,630 now that's a good condition, it'll call the info function. 216 00:10:24,630 --> 00:10:26,970 And afterwards, and this is the purpose of spies, 217 00:10:26,970 --> 00:10:28,830 after you called the function of interest, 218 00:10:28,830 --> 00:10:32,557 you can then check the info spy to say, 219 00:10:32,557 --> 00:10:34,530 "Has that been called, 220 00:10:34,530 --> 00:10:36,300 and has it been called with that information?" 221 00:10:36,300 --> 00:10:37,860 Because let me just remind you 222 00:10:37,860 --> 00:10:39,543 how the divide function worked. 223 00:10:43,290 --> 00:10:44,850 Here's my divide function. 224 00:10:44,850 --> 00:10:47,253 So if the denominator isn't zero, 225 00:10:49,321 --> 00:10:52,827 it should have called the info function with that parameter. 226 00:10:53,910 --> 00:10:56,737 So we're gonna check the spy now to say, 227 00:10:56,737 --> 00:10:59,130 "Well, did it call the info function 228 00:10:59,130 --> 00:11:01,500 with that parameter, with that string?" 229 00:11:01,500 --> 00:11:04,830 And that's what my check does, 230 00:11:04,830 --> 00:11:06,750 it's verifying that having done 231 00:11:06,750 --> 00:11:10,350 that, the info mock function that well, you know, 232 00:11:10,350 --> 00:11:13,680 that spy tells me that the info function was called, 233 00:11:13,680 --> 00:11:16,410 and it was called with these parameters in divide, 234 00:11:16,410 --> 00:11:19,140 with the parameters value A and B at 10 and 20. 235 00:11:19,140 --> 00:11:20,550 We can also verify, 236 00:11:20,550 --> 00:11:23,430 and this is another powerful aspect of spies, 237 00:11:23,430 --> 00:11:26,130 you can also check that a certain function wasn't called. 238 00:11:26,130 --> 00:11:27,750 You can say, "Okay, let's check 239 00:11:27,750 --> 00:11:29,850 that the info function was called. 240 00:11:29,850 --> 00:11:32,580 Let's check that the warning function was not called." 241 00:11:32,580 --> 00:11:34,890 It's important that you didn't call the warn function, 242 00:11:34,890 --> 00:11:37,440 because it's not a warning situation. 243 00:11:37,440 --> 00:11:38,273 And it's important 244 00:11:38,273 --> 00:11:40,380 that the error function wasn't called as well. 245 00:11:40,380 --> 00:11:42,750 So the value of spies, as I can tell you, 246 00:11:42,750 --> 00:11:45,630 how your function interacted with lower level functions, 247 00:11:45,630 --> 00:11:48,060 did it call them, and with what parameters? 248 00:11:48,060 --> 00:11:50,370 And did it not call that function, 249 00:11:50,370 --> 00:11:52,070 and did it not call that function? 250 00:11:53,070 --> 00:11:55,290 Okay, so just to recap, 251 00:11:55,290 --> 00:11:58,560 I invoke the function under test, my divide function. 252 00:11:58,560 --> 00:12:00,750 It will call, well in this situation, 253 00:12:00,750 --> 00:12:02,490 it'll call the info function. 254 00:12:02,490 --> 00:12:05,760 So I verify that it has actually called the info function 255 00:12:05,760 --> 00:12:09,030 with that parameter specified here. 256 00:12:09,030 --> 00:12:12,780 And I also verify that it didn't call the warn function 257 00:12:12,780 --> 00:12:13,893 or the error function. 258 00:12:14,880 --> 00:12:16,140 So that's my first test, 259 00:12:16,140 --> 00:12:18,990 I can run that test like this. 260 00:12:18,990 --> 00:12:19,980 That's the name of the test, 261 00:12:19,980 --> 00:12:22,050 spying on a function, example one. 262 00:12:22,050 --> 00:12:24,660 When I run that test, I ran it earlier, 263 00:12:24,660 --> 00:12:26,160 it displays this. 264 00:12:26,160 --> 00:12:29,070 Well, it does actually output a console message. 265 00:12:29,070 --> 00:12:31,170 It displays an informational message here, 266 00:12:32,640 --> 00:12:33,540 but also, you noticed 267 00:12:33,540 --> 00:12:36,330 that it has passed, everything in there worked. 268 00:12:36,330 --> 00:12:38,520 It has interacted correctly 269 00:12:38,520 --> 00:12:40,023 with the low level functions. 270 00:12:41,460 --> 00:12:43,470 The second test, same idea, 271 00:12:43,470 --> 00:12:46,140 but this time we'll go down the warning route 272 00:12:46,140 --> 00:12:48,120 for the divide function. 273 00:12:48,120 --> 00:12:51,030 So this time, I'm gonna call the divide function, 274 00:12:51,030 --> 00:12:52,860 but I'm gonna pass in zero. 275 00:12:52,860 --> 00:12:55,830 And according to the way the divide function works, 276 00:12:55,830 --> 00:12:59,970 if the denominator is zero, then in that case, 277 00:12:59,970 --> 00:13:01,590 we should, the divide function, 278 00:13:01,590 --> 00:13:03,000 I mean, I've obviously written the code here, 279 00:13:03,000 --> 00:13:04,320 so I know it's gonna happen. 280 00:13:04,320 --> 00:13:07,650 But if I was verifying, I can verify that in that situation, 281 00:13:07,650 --> 00:13:11,070 it should call warn with that parameter. 282 00:13:11,070 --> 00:13:14,190 In divide with the value of A and the value of B. 283 00:13:14,190 --> 00:13:17,160 So I can verify that it does call the warn function, 284 00:13:17,160 --> 00:13:18,960 and that it doesn't call the others. 285 00:13:20,190 --> 00:13:24,450 So here we go, let's call the function and the test, 286 00:13:24,450 --> 00:13:26,950 let's verify that it called the warn function 287 00:13:27,900 --> 00:13:31,080 because it's detected a warning situation. 288 00:13:31,080 --> 00:13:34,770 Let's also verify that it didn't call the info function, 289 00:13:34,770 --> 00:13:35,820 or the mock function. 290 00:13:37,290 --> 00:13:40,740 So all we need to do now is to run this test. 291 00:13:40,740 --> 00:13:43,383 So I can run that test like this, example two, 292 00:13:44,400 --> 00:13:48,090 and it works as well when it called the warning function. 293 00:13:48,090 --> 00:13:50,890 It did actually output a console message with a warning, 294 00:13:51,750 --> 00:13:54,810 and it verifies that it did interact successfully 295 00:13:54,810 --> 00:13:56,100 with those lower level functions. 296 00:13:56,100 --> 00:13:59,430 So the purpose of spying is rather than like, 297 00:13:59,430 --> 00:14:00,900 checking the result, you can check, 298 00:14:00,900 --> 00:14:03,030 how does your function call other functions? 299 00:14:03,030 --> 00:14:04,530 Does it call them properly? 300 00:14:04,530 --> 00:14:06,803 And does it call them with the right parameters?