1 00:00:00,660 --> 00:00:01,890 Instructor: We've got specs in place 2 00:00:01,890 --> 00:00:03,300 around our comment box 3 00:00:03,300 --> 00:00:06,750 and we are correctly calling our action creator 4 00:00:06,750 --> 00:00:10,230 whenever a user types in a comment and then submits it. 5 00:00:10,230 --> 00:00:12,120 So we've got a reasonable idea 6 00:00:12,120 --> 00:00:15,540 that we're calling our saveComment action creator right here 7 00:00:15,540 --> 00:00:17,670 with the comment that the user entered. 8 00:00:17,670 --> 00:00:19,470 That means the last thing that we need to do 9 00:00:19,470 --> 00:00:23,310 is create a reducer for handling this list of comments 10 00:00:23,310 --> 00:00:26,490 and generating our comments piece of state. 11 00:00:26,490 --> 00:00:30,510 We're also going to test this reducer as we develop it. 12 00:00:30,510 --> 00:00:32,880 So let's scaffold out the reducer 13 00:00:32,880 --> 00:00:34,650 and then we'll write all the specs for it 14 00:00:34,650 --> 00:00:37,020 and then we'll implement the reducer. 15 00:00:37,020 --> 00:00:38,790 So inside of our reducer's folder, 16 00:00:38,790 --> 00:00:40,860 inside of the source directory, 17 00:00:40,860 --> 00:00:45,690 I'm gonna create a new file called comments.js. 18 00:00:45,690 --> 00:00:48,720 So this thing right here is gonna be our reducer. 19 00:00:48,720 --> 00:00:51,420 Now we know that our reducer is almost always 20 00:00:51,420 --> 00:00:52,950 have the same signature. 21 00:00:52,950 --> 00:00:57,720 We're always going to export default a function 22 00:00:57,720 --> 00:01:00,000 that receives piece of state, 23 00:01:00,000 --> 00:01:02,250 and we're going to default it to an array 24 00:01:02,250 --> 00:01:04,590 since it's gonna be a list of comments. 25 00:01:04,590 --> 00:01:07,500 And then we're also going to receive actions in here. 26 00:01:07,500 --> 00:01:10,683 So we'll say that, hey, second argument is our action. 27 00:01:11,880 --> 00:01:14,430 So this is really all we need in here for right now 28 00:01:14,430 --> 00:01:17,010 to get us writing some reasonable specs. 29 00:01:17,010 --> 00:01:18,963 So I'll go ahead and save this file. 30 00:01:20,640 --> 00:01:22,980 And then inside of my test directory, 31 00:01:22,980 --> 00:01:27,030 I'm gonna make a new folder called reducers. 32 00:01:27,030 --> 00:01:30,960 And inside of reducers we'll make, 33 00:01:30,960 --> 00:01:35,960 oops, yes, there we go, comments_test.js. 34 00:01:36,120 --> 00:01:37,500 And so here's where we're gonna put 35 00:01:37,500 --> 00:01:40,140 all of our tests around our reducer. 36 00:01:40,140 --> 00:01:43,080 Now for our reducer, we've only got one action type 37 00:01:43,080 --> 00:01:45,450 floating around our entire application. 38 00:01:45,450 --> 00:01:46,920 So here's what we're gonna test 39 00:01:46,920 --> 00:01:48,300 and this is something that's repeatable 40 00:01:48,300 --> 00:01:51,990 for just about every single reducer we create. 41 00:01:51,990 --> 00:01:53,340 Whenever we test a reducer 42 00:01:53,340 --> 00:01:55,650 we're gonna desk test the default case, 43 00:01:55,650 --> 00:01:58,680 which is we pass in an action that we know 44 00:01:58,680 --> 00:02:02,340 that the reducer is not supposed to work with a respond to. 45 00:02:02,340 --> 00:02:04,380 The purpose of this is to really just test 46 00:02:04,380 --> 00:02:07,350 the initial state of the reducer. 47 00:02:07,350 --> 00:02:08,370 We're gonna make sure that hey, 48 00:02:08,370 --> 00:02:10,919 that array that we just defaulted it to 49 00:02:10,919 --> 00:02:14,043 is never gonna get changed accidentally to something else. 50 00:02:15,330 --> 00:02:16,950 The second thing that we're gonna test, 51 00:02:16,950 --> 00:02:19,140 and again this is true of all reducers, 52 00:02:19,140 --> 00:02:22,680 is we're going to test each possible action 53 00:02:22,680 --> 00:02:24,600 that the reducer cares about. 54 00:02:24,600 --> 00:02:26,640 Now, in this application that we're building, 55 00:02:26,640 --> 00:02:29,280 there's only one action type floating around. 56 00:02:29,280 --> 00:02:31,320 So that means only one test here. 57 00:02:31,320 --> 00:02:33,900 But if we had a application with say 58 00:02:33,900 --> 00:02:36,390 20 different action types, 59 00:02:36,390 --> 00:02:39,060 if our reducer only cared about this one action, 60 00:02:39,060 --> 00:02:40,890 or a very single action type, 61 00:02:40,890 --> 00:02:44,070 we would still only have one test. 62 00:02:44,070 --> 00:02:46,620 So let's do some scaffolding for our test here 63 00:02:46,620 --> 00:02:47,643 for our reducer. 64 00:02:48,630 --> 00:02:53,050 We're going to import, export, excuse me, expect 65 00:02:55,140 --> 00:03:00,140 from up one directory test helper. 66 00:03:00,330 --> 00:03:02,010 Again, we're not going to need to bring in 67 00:03:02,010 --> 00:03:03,300 the render component helper 68 00:03:03,300 --> 00:03:06,330 because we're not rendering any components here. 69 00:03:06,330 --> 00:03:08,700 And then the only other thing we need to import in here 70 00:03:08,700 --> 00:03:10,620 is the reducer itself. 71 00:03:10,620 --> 00:03:13,527 So we'll import commentReducer from 72 00:03:17,010 --> 00:03:19,500 and this is another one of those big walks up the tree. 73 00:03:19,500 --> 00:03:21,900 So we'll go up to test, 74 00:03:21,900 --> 00:03:25,530 up to root, into source, into reducers. 75 00:03:25,530 --> 00:03:30,453 So up, up source reducers comments. 76 00:03:32,580 --> 00:03:34,890 Now, I might have spoken too early when I said 77 00:03:34,890 --> 00:03:38,520 there was only one other thing we had to import here. 78 00:03:38,520 --> 00:03:42,360 I think that we'll also import our action types 79 00:03:42,360 --> 00:03:43,650 and make sure that we're working 80 00:03:43,650 --> 00:03:46,620 with the correct SAVE_COMMENT. 81 00:03:46,620 --> 00:03:47,453 We do wanna make sure 82 00:03:47,453 --> 00:03:50,707 that we are responding correctly to the SAVE_COMMENT. 83 00:03:52,230 --> 00:03:55,003 So we will also import SAVE_COMMENT 84 00:03:56,859 --> 00:04:00,853 from up up source actions types. 85 00:04:03,300 --> 00:04:04,710 Okay, so now we can go ahead 86 00:04:04,710 --> 00:04:08,340 and write our two specs around both cases for this reducer, 87 00:04:08,340 --> 00:04:11,910 the default case and the save comment case. 88 00:04:11,910 --> 00:04:15,270 So we'll describe comments reducer, 89 00:04:15,270 --> 00:04:17,760 again, the top level describes purposes 90 00:04:17,760 --> 00:04:19,920 to give a top level description 91 00:04:19,920 --> 00:04:23,640 of exactly what we're gonna be testing inside of this file. 92 00:04:23,640 --> 00:04:28,640 And then we'll say, it handles action with unknown type. 93 00:04:30,240 --> 00:04:33,000 So in other words, if we give this thing an action 94 00:04:33,000 --> 00:04:35,310 with some just super random type 95 00:04:35,310 --> 00:04:37,633 that isn't really supposed to be responded to 96 00:04:37,633 --> 00:04:41,550 in our application, this thing should at least respond 97 00:04:41,550 --> 00:04:44,973 with an array, with an empty array by default. 98 00:04:45,870 --> 00:04:47,490 The other case we'll wanna handle 99 00:04:47,490 --> 00:04:51,967 is it handles action of type SAVE_COMMENT. 100 00:04:55,290 --> 00:04:58,230 Another more concise way that I like to use 101 00:04:58,230 --> 00:05:02,100 in my personal projects where I've got a reasonable idea 102 00:05:02,100 --> 00:05:03,750 that anyone reading this code 103 00:05:03,750 --> 00:05:06,390 or reading my code in the future will know what's going on. 104 00:05:06,390 --> 00:05:09,090 I'll usually just abbreviate all these different types 105 00:05:09,090 --> 00:05:12,330 into something like, I'll just say SAVE_COMMENT by itself. 106 00:05:12,330 --> 00:05:14,910 So anyone who's looking through here, 107 00:05:14,910 --> 00:05:17,040 if a specific case is failing 108 00:05:17,040 --> 00:05:19,860 or if they want to add a specific action type, 109 00:05:19,860 --> 00:05:20,820 they just put an it. 110 00:05:20,820 --> 00:05:21,780 You can just put an it down 111 00:05:21,780 --> 00:05:24,360 with just the type that we're talking about here 112 00:05:24,360 --> 00:05:28,050 as opposed to saying handles action of type, so and so. 113 00:05:28,050 --> 00:05:29,403 Just a little time saver. 114 00:05:31,140 --> 00:05:33,480 All right, let's go ahead and write the test 115 00:05:33,480 --> 00:05:36,330 for the unknown type first. 116 00:05:36,330 --> 00:05:38,670 So before we write the test, let me ask you, 117 00:05:38,670 --> 00:05:41,040 I'm asking you whoever's listening to this. 118 00:05:41,040 --> 00:05:45,810 If we call our reducer with some just super random action, 119 00:05:45,810 --> 00:05:48,150 maybe even action without a type at all, 120 00:05:48,150 --> 00:05:49,440 what do we expect to happen? 121 00:05:49,440 --> 00:05:51,660 What do we expect to get back? 122 00:05:51,660 --> 00:05:52,800 Take a second. 123 00:05:52,800 --> 00:05:54,270 You can even pause the video, 124 00:05:54,270 --> 00:05:55,317 look at the code we have right now 125 00:05:55,317 --> 00:05:57,480 and just say, hey, if I pass in, 126 00:05:57,480 --> 00:05:59,340 let's say no action whatsoever, 127 00:05:59,340 --> 00:06:03,213 what do I really expect my reducer to return by default? 128 00:06:04,290 --> 00:06:06,990 And if you can answer that question yourself, 129 00:06:06,990 --> 00:06:08,940 I encourage you to, again, pause the video 130 00:06:08,940 --> 00:06:11,160 and try writing this expectation here. 131 00:06:11,160 --> 00:06:14,373 Testing is all about practice, all about practice. 132 00:06:16,440 --> 00:06:18,480 So if you wanna give it a shot, go for it. 133 00:06:18,480 --> 00:06:20,853 Otherwise, we'll start in just a second. 134 00:06:24,180 --> 00:06:25,530 All right, So let's give it a shot. 135 00:06:25,530 --> 00:06:30,530 We'll do expect commentReducer, and we're just gonna say 136 00:06:30,630 --> 00:06:33,150 you know what, we're not gonna pass in any initial state 137 00:06:33,150 --> 00:06:36,602 and we're not gonna pass in any action whatsoever. 138 00:06:36,602 --> 00:06:39,060 I want to test that if this thing gets called 139 00:06:39,060 --> 00:06:41,670 with mysterious arguments, we wanna make sure 140 00:06:41,670 --> 00:06:45,120 that it at least returns an empty array. 141 00:06:45,120 --> 00:06:47,363 So I'm gonna expect commentReducer. 142 00:06:49,230 --> 00:06:51,210 And you know what actually this would be a great time 143 00:06:51,210 --> 00:06:54,720 to go look at some of the further documentation. 144 00:06:54,720 --> 00:06:58,323 So let me pull up another HTML document here. 145 00:06:59,880 --> 00:07:03,000 We've been looking at some of the matchers for chai-jquery, 146 00:07:03,000 --> 00:07:05,670 but in this case, I wanna look at some of the matchers 147 00:07:05,670 --> 00:07:08,880 for just chai js by itself. 148 00:07:08,880 --> 00:07:10,020 So the Chai library, 149 00:07:10,020 --> 00:07:12,720 and we'll talk about the purpose of mocha versus chai. 150 00:07:12,720 --> 00:07:16,380 The purpose of chai is just to provide some very low level, 151 00:07:16,380 --> 00:07:19,470 very common, very default assertions. 152 00:07:19,470 --> 00:07:21,850 And so we can expect 153 00:07:26,310 --> 00:07:30,390 that whatever is returned from our reducer, 154 00:07:30,390 --> 00:07:32,940 we know that we want it to be an array by default. 155 00:07:32,940 --> 00:07:34,830 So I'm gonna say that I expect 156 00:07:34,830 --> 00:07:39,210 if I call our comment reducer with no arguments, 157 00:07:39,210 --> 00:07:41,160 I expect the value to be returned 158 00:07:41,160 --> 00:07:43,713 is gonna be an instance of an array. 159 00:07:45,000 --> 00:07:46,860 So let's give that a shot. 160 00:07:46,860 --> 00:07:51,860 We'll say, expect commentReducer to be instance of array. 161 00:07:55,350 --> 00:07:57,570 So keep in mind here that I'm not expecting 162 00:07:57,570 --> 00:08:00,000 the reducer itself to be an array. 163 00:08:00,000 --> 00:08:03,600 I'm expecting whatever the reducer returns to be an array. 164 00:08:03,600 --> 00:08:05,730 We are invoking it here. 165 00:08:05,730 --> 00:08:07,140 So I know the language here 166 00:08:07,140 --> 00:08:09,003 can be just a little bit misleading. 167 00:08:10,230 --> 00:08:11,190 There's one other approach 168 00:08:11,190 --> 00:08:13,710 that I think we could get away with here. 169 00:08:13,710 --> 00:08:16,620 We could probably also try commentReducer 170 00:08:17,790 --> 00:08:22,350 to equal empty array like so. 171 00:08:22,350 --> 00:08:25,260 And so you'll notice that I'm using eql here 172 00:08:25,260 --> 00:08:28,380 as opposed to the full word E Q U A L. 173 00:08:28,380 --> 00:08:31,290 So this equal right here will do a deep comparison 174 00:08:31,290 --> 00:08:34,200 and it'll say, Okay, if this is an array, 175 00:08:34,200 --> 00:08:37,470 I'm gonna make sure that all the values in this array 176 00:08:37,470 --> 00:08:40,590 are equal to the values in this array right here. 177 00:08:40,590 --> 00:08:45,590 Whereas the E Q U A L, equal, the full word equal 178 00:08:46,260 --> 00:08:49,440 checks to see if the array or whatever is right here 179 00:08:49,440 --> 00:08:53,160 is the absolute identical object on either side. 180 00:08:53,160 --> 00:08:57,450 So equal is, the full length equal is sometimes that we use 181 00:08:57,450 --> 00:08:58,560 a little bit more sparingly. 182 00:08:58,560 --> 00:08:59,790 It's more often used with 183 00:08:59,790 --> 00:09:02,670 when we're comparing strings or numbers. 184 00:09:02,670 --> 00:09:04,560 Anyways, let's go ahead and just give this a shot. 185 00:09:04,560 --> 00:09:05,940 Let's see how far we get. 186 00:09:05,940 --> 00:09:07,203 So I'm gonna save this. 187 00:09:08,580 --> 00:09:12,090 Now, I did just create a new spec file, 188 00:09:12,090 --> 00:09:15,213 which means I need to restart my tests, so I'll do so. 189 00:09:24,000 --> 00:09:24,960 Huh, interesting. 190 00:09:24,960 --> 00:09:28,710 So we got expected undefined to be an instance of array. 191 00:09:28,710 --> 00:09:29,543 But you know what? 192 00:09:29,543 --> 00:09:30,540 Come to think of it, 193 00:09:30,540 --> 00:09:32,640 this is actually very reasonable right now 194 00:09:32,640 --> 00:09:36,570 because right now we are defaulting the array. 195 00:09:36,570 --> 00:09:38,580 We're defaulting state to an array, 196 00:09:38,580 --> 00:09:41,250 but we're not returning state by default. 197 00:09:41,250 --> 00:09:45,060 So let's improve this to return state. 198 00:09:45,060 --> 00:09:48,780 And now sure enough, everything is passing, very good. 199 00:09:48,780 --> 00:09:51,630 So just as a little exploration there, 200 00:09:51,630 --> 00:09:56,310 we were able to use either the result of commentReducer 201 00:09:56,310 --> 00:09:58,200 should be an instance of array 202 00:09:58,200 --> 00:10:01,050 or it should literally be an empty array. 203 00:10:01,050 --> 00:10:03,210 It's really up to you which direction you wanna go. 204 00:10:03,210 --> 00:10:06,000 I would probably stick with this second expectation 205 00:10:06,000 --> 00:10:08,820 down here just because it is specifically asserting 206 00:10:08,820 --> 00:10:10,530 that the array is gonna be empty. 207 00:10:10,530 --> 00:10:14,760 Whereas up here we're asserting that it's just of type array 208 00:10:14,760 --> 00:10:17,280 and it's not necessarily saying that it should be empty. 209 00:10:17,280 --> 00:10:20,550 So I think in my case, I'm gonna stick with this reducer 210 00:10:20,550 --> 00:10:22,550 or excuse me, this assertion right here. 211 00:10:24,090 --> 00:10:26,973 I'm gonna save and we're still passing, very good. 212 00:10:27,960 --> 00:10:29,400 So we now need to handle the case 213 00:10:29,400 --> 00:10:33,300 of it handles action of type SAVE_COMMENT. 214 00:10:33,300 --> 00:10:36,180 So whenever we're handling a reducer test 215 00:10:36,180 --> 00:10:37,800 where we're going to craft an action, 216 00:10:37,800 --> 00:10:40,170 where we'll craft the action ahead of time 217 00:10:40,170 --> 00:10:42,240 and then we'll pass it into the reducer 218 00:10:42,240 --> 00:10:43,860 with some default state, 219 00:10:43,860 --> 00:10:45,900 and then we'll expect that whatever gets returned 220 00:10:45,900 --> 00:10:49,443 from the reducer is the state that we expect. 221 00:10:50,880 --> 00:10:53,310 So we'll first craft our action. 222 00:10:53,310 --> 00:10:57,550 We're gonna have an action of type SAVE_COMMENT 223 00:10:59,460 --> 00:11:01,983 and we'll have a payload of new comment. 224 00:11:04,530 --> 00:11:08,250 So now if I put this into commentReducer, 225 00:11:08,250 --> 00:11:10,440 and remember the first argument to my reducer 226 00:11:10,440 --> 00:11:11,550 is the initial state. 227 00:11:11,550 --> 00:11:15,960 So I'll put in an initial state of empty array. 228 00:11:15,960 --> 00:11:18,573 And then the second is the action. 229 00:11:20,370 --> 00:11:25,200 So if I call my commentReducer with an empty array 230 00:11:25,200 --> 00:11:27,821 and an action of type SAVE_COMMENT 231 00:11:27,821 --> 00:11:29,460 with a payload of new comment, 232 00:11:29,460 --> 00:11:32,340 basically my expectation here is that I should see 233 00:11:32,340 --> 00:11:34,860 this new comment be added into this array. 234 00:11:34,860 --> 00:11:36,480 Because ultimately that's all this app 235 00:11:36,480 --> 00:11:37,380 is really trying to do. 236 00:11:37,380 --> 00:11:40,200 It's trying to create a list of comments, 237 00:11:40,200 --> 00:11:42,420 which are gonna live inside of an array. 238 00:11:42,420 --> 00:11:44,820 Now the knowledge of that is the fact 239 00:11:44,820 --> 00:11:46,830 that I wanted to add it to an array. 240 00:11:46,830 --> 00:11:49,740 Kind of, I only personally know that 241 00:11:49,740 --> 00:11:51,930 because I know how to build this application. 242 00:11:51,930 --> 00:11:54,960 If that wasn't immediately obvious to you, it's no problem. 243 00:11:54,960 --> 00:11:56,460 This is part of the difficulty of testing. 244 00:11:56,460 --> 00:11:58,020 It's kind of, it really requires you 245 00:11:58,020 --> 00:12:00,750 to have a very deep understanding of the software 246 00:12:00,750 --> 00:12:03,000 that you wanna build and the code that you wanna write. 247 00:12:03,000 --> 00:12:05,200 And that's really a positive and a negative. 248 00:12:06,900 --> 00:12:09,810 So I expect to see an array back with this 249 00:12:09,810 --> 00:12:13,020 that has one string in it of new comment. 250 00:12:13,020 --> 00:12:18,020 So in this case, we'll say to eql new comment. 251 00:12:20,310 --> 00:12:21,510 So let's save this. 252 00:12:21,510 --> 00:12:24,030 And okay, so we've got our error now 253 00:12:24,030 --> 00:12:27,330 because we aren't handling this case inside of our reducer. 254 00:12:27,330 --> 00:12:29,820 Let's go ahead and continue inside the next section 255 00:12:29,820 --> 00:12:32,400 where we will finish wiring up the reducer 256 00:12:32,400 --> 00:12:34,860 and then we'll do a little bit of review 257 00:12:34,860 --> 00:12:36,860 of the specs that we just wrote as well.