1 00:00:00,000 --> 00:00:02,450 [MUSIC PLAYING] 2 00:00:02,450 --> 00:00:17,660 3 00:00:17,660 --> 00:00:21,440 JORDAN HAYASHI: Hello, and welcome for lecture 12, deploying and testing. 4 00:00:21,440 --> 00:00:23,330 So last week, we talked about performance. 5 00:00:23,330 --> 00:00:25,160 We talked about the trade-offs that you get 6 00:00:25,160 --> 00:00:27,320 when you do some performance optimization, that 7 00:00:27,320 --> 00:00:29,480 just being additional complexity. 8 00:00:29,480 --> 00:00:32,870 We talked about a couple of different ways to test against performance, one 9 00:00:32,870 --> 00:00:34,520 being the React Native perf monitors. 10 00:00:34,520 --> 00:00:38,600 So it's built into your phone, and it allows 11 00:00:38,600 --> 00:00:40,920 you to see how many frames per second you run. 12 00:00:40,920 --> 00:00:42,920 We talked about the Chrome Performance Profiler, 13 00:00:42,920 --> 00:00:46,730 which actually runs your JavaScript code within Chrome 14 00:00:46,730 --> 00:00:50,420 and shows you a flame chart of all of the components that are rendering. 15 00:00:50,420 --> 00:00:53,810 We talked about a few different common inefficiencies that we see in React. 16 00:00:53,810 --> 00:00:56,120 One would be re-rendering too often, another 17 00:00:56,120 --> 00:00:58,760 being unnecessarily changing props, which may actually 18 00:00:58,760 --> 00:01:01,100 contribute to re-rendering too often. 19 00:01:01,100 --> 00:01:03,530 And then lastly, just unnecessary logic. 20 00:01:03,530 --> 00:01:06,110 And then we ended the lecture with a demo 21 00:01:06,110 --> 00:01:08,660 of this animated API, which allows us to run 22 00:01:08,660 --> 00:01:14,960 some calculations on the native side of things rather than within JavaScript. 23 00:01:14,960 --> 00:01:21,620 So this week, we'll give a high-level talk about deploying apps. 24 00:01:21,620 --> 00:01:26,480 So the way that you deploy in Expo is by building the app locally, and then 25 00:01:26,480 --> 00:01:28,970 uploading it to the store. 26 00:01:28,970 --> 00:01:32,720 Before you do that, you have to make sure to set the correct metadata 27 00:01:32,720 --> 00:01:34,070 in your app.json file. 28 00:01:34,070 --> 00:01:38,480 And you can find out exactly what those are at this Expo documentation link 29 00:01:38,480 --> 00:01:40,130 here. 30 00:01:40,130 --> 00:01:42,170 Then you go ahead and build the app using 31 00:01:42,170 --> 00:01:45,610 this command-line utility called exp. 32 00:01:45,610 --> 00:01:47,780 It's basically just an alternative to the XDE 33 00:01:47,780 --> 00:01:54,080 because the XDE does not allow you to build the app within that GUI. 34 00:01:54,080 --> 00:01:56,690 The way to do this is to install the script. 35 00:01:56,690 --> 00:01:59,750 So you do npm install global exp, just like how 36 00:01:59,750 --> 00:02:02,210 you install a bunch of other libraries. 37 00:02:02,210 --> 00:02:08,612 You then build it by doing either build colon iOS or exp build android. 38 00:02:08,612 --> 00:02:10,820 What that does is it actually sends your JavaScript-- 39 00:02:10,820 --> 00:02:13,970 your whole bundle, actually-- over to Expo's servers, 40 00:02:13,970 --> 00:02:16,640 where it does the entire build. 41 00:02:16,640 --> 00:02:19,970 And then Expo uploads that build to S3. 42 00:02:19,970 --> 00:02:23,870 The way that you get that build onto your computer is to run this [? ex ?] 43 00:02:23,870 --> 00:02:27,562 [? build ?] [? status, ?] which if you run it while it's building, 44 00:02:27,562 --> 00:02:29,270 it will let you know it's still building. 45 00:02:29,270 --> 00:02:32,060 But once it's done, it will spit out a URL for you, 46 00:02:32,060 --> 00:02:37,389 which is the link to your app in Amazon's S3 storage system. 47 00:02:37,389 --> 00:02:39,680 And then you can just cut and paste that into a browser 48 00:02:39,680 --> 00:02:42,800 and go ahead and download that file. 49 00:02:42,800 --> 00:02:45,860 Then you can upload it to the appropriate store. 50 00:02:45,860 --> 00:02:50,990 So the way that you do that depends on whether you're doing iOS or Android. 51 00:02:50,990 --> 00:02:52,970 And here's a couple of documentation links 52 00:02:52,970 --> 00:02:54,428 that talk you through that process. 53 00:02:54,428 --> 00:02:56,780 54 00:02:56,780 --> 00:02:58,640 One great thing that you can do with Expo 55 00:02:58,640 --> 00:03:03,147 is to deploy new JavaScript by republishing. 56 00:03:03,147 --> 00:03:04,730 And that's called over-the-air update. 57 00:03:04,730 --> 00:03:08,840 So you actually upload a new bundle because the way that your app works, 58 00:03:08,840 --> 00:03:11,760 it's really just a shell that's running JavaScript code. 59 00:03:11,760 --> 00:03:16,070 And so you can go ahead and download some new JavaScript from the web 60 00:03:16,070 --> 00:03:17,610 and run that as your application. 61 00:03:17,610 --> 00:03:22,400 And so by republishing from the XDE or using that exp script, 62 00:03:22,400 --> 00:03:25,130 you can deploy a new JavaScript bundle and push it 63 00:03:25,130 --> 00:03:29,480 over the air to your clients without having them redownload 64 00:03:29,480 --> 00:03:34,160 the app from the app store itself. 65 00:03:34,160 --> 00:03:36,980 Though if you want to change any application metadata, 66 00:03:36,980 --> 00:03:43,070 like the name of it, then you're going to have to resubmit it to the store. 67 00:03:43,070 --> 00:03:46,670 So doing this over-the-air update thing is very, very powerful, 68 00:03:46,670 --> 00:03:50,455 but also slightly dangerous because you can actually upload JavaScript 69 00:03:50,455 --> 00:03:52,080 that crashes your app and doesn't work. 70 00:03:52,080 --> 00:03:56,510 And it won't actually be caught by their respective app store people 71 00:03:56,510 --> 00:03:58,140 because they never see it. 72 00:03:58,140 --> 00:04:00,590 It just goes straight to the cloud. 73 00:04:00,590 --> 00:04:03,420 And then your users go ahead and download that. 74 00:04:03,420 --> 00:04:10,130 And so how do we ensure that everything works as expected before deploying? 75 00:04:10,130 --> 00:04:12,950 So you do that by testing. 76 00:04:12,950 --> 00:04:15,740 And so when we use the word "testing," we generally 77 00:04:15,740 --> 00:04:19,010 are referring to automated testing as opposed 78 00:04:19,010 --> 00:04:21,980 to manual testing or doing quality assurance, 79 00:04:21,980 --> 00:04:24,470 whereby you just open up your app manually and play 80 00:04:24,470 --> 00:04:26,595 with all of the features that you have to make sure 81 00:04:26,595 --> 00:04:28,950 that they work appropriately. 82 00:04:28,950 --> 00:04:31,070 And so why might we want to do this? 83 00:04:31,070 --> 00:04:33,650 Well, as your application grows in size, manual testing 84 00:04:33,650 --> 00:04:36,890 gets more and more difficult. And more complexity 85 00:04:36,890 --> 00:04:38,939 means there are more points of failure. 86 00:04:38,939 --> 00:04:40,730 And so if you imagine if every single week, 87 00:04:40,730 --> 00:04:46,810 you add 10 more features, that's growing linearly every week. 88 00:04:46,810 --> 00:04:50,594 And so even though you keep adding the same number of features every week, 89 00:04:50,594 --> 00:04:52,760 the amount that you have to test every week actually 90 00:04:52,760 --> 00:04:55,110 goes up by the integral of that. 91 00:04:55,110 --> 00:04:57,710 So you have a linear growth in the number of features 92 00:04:57,710 --> 00:05:00,780 that you have to test every single week. 93 00:05:00,780 --> 00:05:04,100 So by adding a test suite, you can ensure that you catch all of your bugs 94 00:05:04,100 --> 00:05:05,560 before they get shipped. 95 00:05:05,560 --> 00:05:07,310 Because the last thing that you want to do 96 00:05:07,310 --> 00:05:10,610 is actually upload some broken code, because then all of your users 97 00:05:10,610 --> 00:05:12,870 will get a broken app. 98 00:05:12,870 --> 00:05:16,440 But how do we know which parts of our app to test? 99 00:05:16,440 --> 00:05:19,660 There's this theoretical structure called the test pyramid. 100 00:05:19,660 --> 00:05:25,310 And it determines a methodology for determining test scale or granularity. 101 00:05:25,310 --> 00:05:28,660 So at the very bottom of the pyramid is what's called a unit test. 102 00:05:28,660 --> 00:05:31,510 And this tests an individual unit of code. 103 00:05:31,510 --> 00:05:36,250 And generally, that's either a function or a class or a method. 104 00:05:36,250 --> 00:05:38,860 Then you have integration or service tests, 105 00:05:38,860 --> 00:05:43,330 which allow you to test the integration of multiple of these pieces of code 106 00:05:43,330 --> 00:05:45,520 and how they work together. 107 00:05:45,520 --> 00:05:48,590 And this is completely independent of the UI. 108 00:05:48,590 --> 00:05:51,520 Which brings us to the last one, the UI tests, or end to end. 109 00:05:51,520 --> 00:05:54,220 And this allows us to test a feature thoroughly, 110 00:05:54,220 --> 00:05:57,160 including the UI and network calls and everything. 111 00:05:57,160 --> 00:06:01,720 So it's basically from one end of your code all the way to the other, 112 00:06:01,720 --> 00:06:04,185 basically what a user would be doing themselves. 113 00:06:04,185 --> 00:06:06,920 114 00:06:06,920 --> 00:06:09,470 So how are we going to write some unit tests? 115 00:06:09,470 --> 00:06:11,480 And so as we talked about in the last slide, 116 00:06:11,480 --> 00:06:14,240 this is testing an individual unit of code, 117 00:06:14,240 --> 00:06:17,630 like a function or a class or a method. 118 00:06:17,630 --> 00:06:20,570 One great thing about unit tests is they're very, very granular. 119 00:06:20,570 --> 00:06:23,210 So you know exactly where your code is breaking. 120 00:06:23,210 --> 00:06:26,750 And that makes it very easy to tell what you need to go fix. 121 00:06:26,750 --> 00:06:30,020 And so the very most basic unit test is just 122 00:06:30,020 --> 00:06:33,164 a function that lets you know when any behavior is unexpected. 123 00:06:33,164 --> 00:06:35,330 And so let's go ahead and write our first unit test. 124 00:06:35,330 --> 00:06:38,240 125 00:06:38,240 --> 00:06:41,240 So I'm going to make a new directory called testing. 126 00:06:41,240 --> 00:06:45,030 And inside that, we're going to go ahead and write our first test. 127 00:06:45,030 --> 00:06:50,660 And so let's write a very simple function, maybe something like sum. 128 00:06:50,660 --> 00:06:53,090 And what sum does is it's just a function that 129 00:06:53,090 --> 00:06:55,020 takes a couple of numbers. 130 00:06:55,020 --> 00:06:56,210 Let's do function sum. 131 00:06:56,210 --> 00:06:59,275 That takes an x and a y. 132 00:06:59,275 --> 00:07:01,400 And let's just return the sum of those two numbers. 133 00:07:01,400 --> 00:07:04,430 So return x plus y. 134 00:07:04,430 --> 00:07:06,420 So pretty simple. 135 00:07:06,420 --> 00:07:09,500 I'm pretty confident that this code does what I think it does. 136 00:07:09,500 --> 00:07:11,420 Let's go ahead and write some tests anyway. 137 00:07:11,420 --> 00:07:14,790 And so how might we go about doing that? 138 00:07:14,790 --> 00:07:17,190 Well, we could write a function that does that. 139 00:07:17,190 --> 00:07:22,530 Or we could just do console.assert, which is basically saying, 140 00:07:22,530 --> 00:07:25,940 I'm going to assert that this thing is true, and if it's not true, 141 00:07:25,940 --> 00:07:27,440 then throw an error. 142 00:07:27,440 --> 00:07:35,480 And so let's just assert that sum of 1 and 1 gives us 2. 143 00:07:35,480 --> 00:07:44,210 And if it doesn't, then we can throw an error that says error summing 1 and 1. 144 00:07:44,210 --> 00:07:47,120 So we can save this and run it using Node. 145 00:07:47,120 --> 00:07:50,390 And we get no output, which is a good thing because if there's no error, 146 00:07:50,390 --> 00:07:52,389 it means our assert passed. 147 00:07:52,389 --> 00:07:54,680 And so let's see what this looks like if we had written 148 00:07:54,680 --> 00:07:56,420 assert that doesn't pass. 149 00:07:56,420 --> 00:08:01,530 And so say we asserted that 1 and 1 was actually 3. 150 00:08:01,530 --> 00:08:04,500 And let me go ahead and quiet this ESLint. 151 00:08:04,500 --> 00:08:14,470 152 00:08:14,470 --> 00:08:20,877 So if my now assert that sum of 1 and 1 is 3, then when we run this, 153 00:08:20,877 --> 00:08:21,960 we get an assertion error. 154 00:08:21,960 --> 00:08:24,014 It says assertion error. 155 00:08:24,014 --> 00:08:24,930 Error summing 1 and 1. 156 00:08:24,930 --> 00:08:28,570 And so we just effectively wrote our very first test. 157 00:08:28,570 --> 00:08:42,549 So let's first fix this and make sure it passes and maybe write a couple 158 00:08:42,549 --> 00:08:43,049 other tests. 159 00:08:43,049 --> 00:08:50,075 We can do console.assert that summing 0 and 0 gives us 0. 160 00:08:50,075 --> 00:08:58,190 161 00:08:58,190 --> 00:09:07,420 And maybe a last one that summing 20 and 30 gives us 50. 162 00:09:07,420 --> 00:09:13,530 163 00:09:13,530 --> 00:09:16,860 20 and 30. 164 00:09:16,860 --> 00:09:20,700 And we can just sanity check to make sure this actually works. 165 00:09:20,700 --> 00:09:21,210 And it does. 166 00:09:21,210 --> 00:09:21,710 Great. 167 00:09:21,710 --> 00:09:24,540 So we just wrote our first simple test. 168 00:09:24,540 --> 00:09:29,640 And so one thing that you may notice is that we have our tests directly 169 00:09:29,640 --> 00:09:33,575 in the same file as our actual function. 170 00:09:33,575 --> 00:09:39,660 And so if we were to write something like add with an x and y-- 171 00:09:39,660 --> 00:09:47,710 or not add, but maybe multiply, now if we want to add a test to this, 172 00:09:47,710 --> 00:09:49,930 we're going to have to add some console.asserts. 173 00:09:49,930 --> 00:09:53,950 And suddenly, this single file starts to get a little bit noisy. 174 00:09:53,950 --> 00:09:57,160 And so just like we've done in other examples, 175 00:09:57,160 --> 00:10:00,320 we might want to start breaking out things into separate files. 176 00:10:00,320 --> 00:10:07,210 And so maybe the test should not be in the same exact file as the functions. 177 00:10:07,210 --> 00:10:09,185 Maybe we should add it to its own test file. 178 00:10:09,185 --> 00:10:10,810 And so let's go ahead and do that here. 179 00:10:10,810 --> 00:10:13,510 180 00:10:13,510 --> 00:10:24,203 So let's save that, and then create a new file called sum.test.js. 181 00:10:24,203 --> 00:10:30,580 182 00:10:30,580 --> 00:10:34,060 And let's just move all of our asserts over to this file. 183 00:10:34,060 --> 00:10:39,175 184 00:10:39,175 --> 00:10:44,640 And you may notice that if I try to run that sum.test.js file, 185 00:10:44,640 --> 00:10:47,280 it's going to error because sum is not actually defined. 186 00:10:47,280 --> 00:10:50,280 And so we're going to have to bring that function called sum 187 00:10:50,280 --> 00:10:52,570 from sum.js into its test file. 188 00:10:52,570 --> 00:10:56,130 189 00:10:56,130 --> 00:10:58,740 And since we're working in Node, we'll go ahead 190 00:10:58,740 --> 00:11:00,990 and use that require statement. 191 00:11:00,990 --> 00:11:04,230 So const sum equals require ./sum.js. 192 00:11:04,230 --> 00:11:07,500 193 00:11:07,500 --> 00:11:18,180 And then just make sure that in test.js or in sum.js, 194 00:11:18,180 --> 00:11:24,030 we need to just make sure that we set our module's exports to be sum. 195 00:11:24,030 --> 00:11:31,869 And so this is basically the same way of doing export default in ES6 196 00:11:31,869 --> 00:11:34,410 is just the way of writing it in Node, since Node doesn't yet 197 00:11:34,410 --> 00:11:37,030 support import and export syntax. 198 00:11:37,030 --> 00:11:40,530 So let's just do module.exports equals sum. 199 00:11:40,530 --> 00:11:46,781 And then now we can try to do node sum.test.js, and no errors. 200 00:11:46,781 --> 00:11:47,280 Great. 201 00:11:47,280 --> 00:11:52,230 So what happens if we change sum.js? 202 00:11:52,230 --> 00:11:56,790 Maybe we actually add a bug where rather than doing x plus y, 203 00:11:56,790 --> 00:12:01,920 we do x plus y plus y. 204 00:12:01,920 --> 00:12:07,352 Now if we run our tests, we see that we get an error summing 1 and 1. 205 00:12:07,352 --> 00:12:09,060 But it doesn't run the rest of our tests. 206 00:12:09,060 --> 00:12:11,045 It just stops at the first error. 207 00:12:11,045 --> 00:12:13,170 And so that's a little bit of a downside of the way 208 00:12:13,170 --> 00:12:16,009 that we've currently been implementing our tests. 209 00:12:16,009 --> 00:12:18,300 And so there are these things called testing frameworks 210 00:12:18,300 --> 00:12:20,110 that give you additional benefits. 211 00:12:20,110 --> 00:12:22,440 One of them is that they run all of the tests 212 00:12:22,440 --> 00:12:26,190 instead of just failing on the first error, like we just saw. 213 00:12:26,190 --> 00:12:30,420 Another great thing is it gives you pretty output because currently, we 214 00:12:30,420 --> 00:12:33,930 just get this assertion error, which is informative, 215 00:12:33,930 --> 00:12:37,650 but it doesn't really look all that great. 216 00:12:37,650 --> 00:12:40,620 It also has this cool benefit where it can automatically watch 217 00:12:40,620 --> 00:12:42,190 for any changes in our application. 218 00:12:42,190 --> 00:12:45,030 So as we change our logic, the test can run automatically 219 00:12:45,030 --> 00:12:50,650 without us having to remember to run them before even checking them 220 00:12:50,650 --> 00:12:54,439 in or sending them in a new deploy. 221 00:12:54,439 --> 00:12:57,480 And lastly, they give you these things called mock functions, which we'll 222 00:12:57,480 --> 00:12:58,910 take a look at it in a little bit. 223 00:12:58,910 --> 00:13:01,392 224 00:13:01,392 --> 00:13:04,350 So the testing framework that we're going to be looking at this lecture 225 00:13:04,350 --> 00:13:06,090 is called Jest. 226 00:13:06,090 --> 00:13:08,640 And so if you look up Jest, what you see is 227 00:13:08,640 --> 00:13:14,070 this thing called Delightful JavaScript Testing, which is a bold claim. 228 00:13:14,070 --> 00:13:17,001 But we'll see that it is pretty great to work with. 229 00:13:17,001 --> 00:13:19,750 So this is a testing framework written by our friends at Facebook, 230 00:13:19,750 --> 00:13:23,520 so the same people who wrote React Native. 231 00:13:23,520 --> 00:13:29,230 And the way to install it is doing npm install --save-dev jest. 232 00:13:29,230 --> 00:13:36,300 And so just to do that here, we can do npm install dev jest. 233 00:13:36,300 --> 00:13:42,265 So there's a shorthand to just do npm i -d rather than npm install --save-dev. 234 00:13:42,265 --> 00:13:44,970 And so this goes ahead and installs Jest. 235 00:13:44,970 --> 00:13:50,070 And as it's installing, the way to run it is doing npx jest. 236 00:13:50,070 --> 00:13:56,510 Make sure if you want to use the npx command, it's built into NPM 5 237 00:13:56,510 --> 00:13:58,770 and above. 238 00:13:58,770 --> 00:14:01,690 And I believe can install it otherwise. 239 00:14:01,690 --> 00:14:07,050 But in NPM version 5 and above, it's automatically bundled. 240 00:14:07,050 --> 00:14:11,180 But the easier way to run it is just by adding a script to your package.json. 241 00:14:11,180 --> 00:14:17,040 And so just like in earlier examples, we added something 242 00:14:17,040 --> 00:14:21,240 to package.json, which might be, like, linting. 243 00:14:21,240 --> 00:14:27,930 We can also add something like test, where we say if we run npm run test, 244 00:14:27,930 --> 00:14:29,910 it's just going to run Jest. 245 00:14:29,910 --> 00:14:30,410 Jest. 246 00:14:30,410 --> 00:14:33,060 247 00:14:33,060 --> 00:14:39,630 And so now we can run npx jest, and we see that it does run. 248 00:14:39,630 --> 00:14:42,510 249 00:14:42,510 --> 00:14:45,720 It actually ran our sum.test.js file because it's 250 00:14:45,720 --> 00:14:52,470 smart enough to know that anything something.test.js, it should just run. 251 00:14:52,470 --> 00:14:57,121 Or we could run npm run test, and it will do the exact same thing. 252 00:14:57,121 --> 00:14:58,620 There's actually shorthand for this. 253 00:14:58,620 --> 00:15:01,290 We can do npm test. 254 00:15:01,290 --> 00:15:04,770 Or even shorter hand, we can do npm t. 255 00:15:04,770 --> 00:15:07,470 So all of those four commands all do the same exact thing. 256 00:15:07,470 --> 00:15:11,357 257 00:15:11,357 --> 00:15:14,440 So the way that this works is it will automatically find and run any files 258 00:15:14,440 --> 00:15:20,560 that end in .test.js or any other regex expression that you specify. 259 00:15:20,560 --> 00:15:24,190 But for now, we're just going to be using that .test.js. 260 00:15:24,190 --> 00:15:27,760 And so now let's rewrite our sum.test.js. 261 00:15:27,760 --> 00:15:32,200 Rather than using console.assert, let's go ahead and use Jest. 262 00:15:32,200 --> 00:15:38,323 263 00:15:38,323 --> 00:15:45,800 So the way that we do this is we just replace that console.assert with jest. 264 00:15:45,800 --> 00:15:49,690 And so the syntax for that is to define a test. 265 00:15:49,690 --> 00:15:55,440 So you just do test, and then a string of what you're actually testing here. 266 00:15:55,440 --> 00:15:56,710 And so let's do-- 267 00:15:56,710 --> 00:16:03,250 let's test that sums 1 and 1. 268 00:16:03,250 --> 00:16:05,170 And now we have a test for summing 1 and 1. 269 00:16:05,170 --> 00:16:14,470 We can do the same thing for sums 0 and 0, and lastly, 20 and 30. 270 00:16:14,470 --> 00:16:20,080 271 00:16:20,080 --> 00:16:25,770 And if we now run this, we see that it will find the tests. 272 00:16:25,770 --> 00:16:29,070 And it just skips all of them because we didn't actually 273 00:16:29,070 --> 00:16:30,760 specify what they were supposed to do. 274 00:16:30,760 --> 00:16:33,035 But it went ahead and found all three of the tests. 275 00:16:33,035 --> 00:16:36,810 And so now let's go ahead and define what those tests should actually do. 276 00:16:36,810 --> 00:16:40,450 277 00:16:40,450 --> 00:16:46,900 So how are we going to define this test summing 1 and 1? 278 00:16:46,900 --> 00:16:50,790 So first, let me go ahead and let ESLint know that there 279 00:16:50,790 --> 00:16:57,390 are a few global functions called test. 280 00:16:57,390 --> 00:17:02,080 281 00:17:02,080 --> 00:17:07,570 So now we can say, how are we going to test that we correctly sum 1 and 1? 282 00:17:07,570 --> 00:17:09,569 And so the way to do that is to pass a callback. 283 00:17:09,569 --> 00:17:14,200 284 00:17:14,200 --> 00:17:20,569 And we can say we're going to expect that if we sum 1 and 1, it should be 2. 285 00:17:20,569 --> 00:17:22,450 And so the syntax for doing that in Jest is 286 00:17:22,450 --> 00:17:34,699 you can do expect something-- so the expression here is 1 and 1.toBe, 287 00:17:34,699 --> 00:17:36,240 and then whatever we expect it to be. 288 00:17:36,240 --> 00:17:39,860 So in this case, it will just be 2. 289 00:17:39,860 --> 00:17:45,444 So we can save that, and then let ESLint know that there are 290 00:17:45,444 --> 00:17:46,985 a couple other globals called expect. 291 00:17:46,985 --> 00:17:53,020 292 00:17:53,020 --> 00:18:02,840 And then now if we run this, we can see that it finds it, and it runs here. 293 00:18:02,840 --> 00:18:04,010 We expected it to be 2. 294 00:18:04,010 --> 00:18:04,790 We got 3. 295 00:18:04,790 --> 00:18:05,320 Why is that? 296 00:18:05,320 --> 00:18:08,960 Because a while back, in order to show that we can fail a test, 297 00:18:08,960 --> 00:18:12,140 we actually changed our implementation of sum. 298 00:18:12,140 --> 00:18:15,410 And so we should probably fix that to make it correct. 299 00:18:15,410 --> 00:18:18,270 300 00:18:18,270 --> 00:18:18,770 So great. 301 00:18:18,770 --> 00:18:21,390 Our test caught an illogical bug. 302 00:18:21,390 --> 00:18:24,020 So now let's go ahead and run npm test again, 303 00:18:24,020 --> 00:18:28,250 and we'll see that now it passes. 304 00:18:28,250 --> 00:18:31,990 And it gives us a nice little green check mark next to our sums 305 00:18:31,990 --> 00:18:33,960 1 and 1 test. 306 00:18:33,960 --> 00:18:36,550 So let's go ahead and add the rest of our tests. 307 00:18:36,550 --> 00:18:40,960 308 00:18:40,960 --> 00:18:48,570 So here, we expect this to have a value, as well. 309 00:18:48,570 --> 00:18:56,610 So we can say expect sum 0 and 0 to be 0. 310 00:18:56,610 --> 00:19:06,570 And lastly, summing 20 and 30, we expect that if we sum 20 and 30, 311 00:19:06,570 --> 00:19:09,240 we expect that to be 50. 312 00:19:09,240 --> 00:19:12,160 And so now our tests are actually a little bit more readable. 313 00:19:12,160 --> 00:19:15,280 You can basically just read the code, and you have the tests. 314 00:19:15,280 --> 00:19:17,950 So test that it sums 1 and 1. 315 00:19:17,950 --> 00:19:18,700 How do we do that? 316 00:19:18,700 --> 00:19:20,790 Well, we expect the sum of 1 and 1 to be 2. 317 00:19:20,790 --> 00:19:22,680 So it reads almost like English. 318 00:19:22,680 --> 00:19:24,390 So let's go ahead and run all of these. 319 00:19:24,390 --> 00:19:27,950 320 00:19:27,950 --> 00:19:31,750 And we see that all three pass here. 321 00:19:31,750 --> 00:19:37,314 And so I talked about how Jest can automatically watch all these files. 322 00:19:37,314 --> 00:19:38,480 But I haven't been doing it. 323 00:19:38,480 --> 00:19:41,450 I've been quitting my file, then rerunning npm test. 324 00:19:41,450 --> 00:19:45,150 And so let's also add a script that allows us to watch the files. 325 00:19:45,150 --> 00:19:52,400 So the way to do that is we can just do npm test, 326 00:19:52,400 --> 00:19:57,980 and then pass it a command-line flag called watch. 327 00:19:57,980 --> 00:20:01,125 And we'll go ahead and run jest watch for us. 328 00:20:01,125 --> 00:20:02,000 And now it'll run it. 329 00:20:02,000 --> 00:20:07,040 330 00:20:07,040 --> 00:20:13,585 Let me first quit and create a separate pane. 331 00:20:13,585 --> 00:20:22,350 332 00:20:22,350 --> 00:20:28,780 So if I do npm test and tell it to watch, then it will start watching. 333 00:20:28,780 --> 00:20:33,630 And then I can flip over into a new pane, open up sum.test.js. 334 00:20:33,630 --> 00:20:38,160 335 00:20:38,160 --> 00:20:42,530 And if I add a new test-- 336 00:20:42,530 --> 00:20:46,950 let's do 20 and 22. 337 00:20:46,950 --> 00:20:51,810 And we expect that to be 42. 338 00:20:51,810 --> 00:20:54,150 I'll save, and I'll hop over to the new frame. 339 00:20:54,150 --> 00:20:57,430 And we see that it already ran that test for us automatically. 340 00:20:57,430 --> 00:21:00,670 And so it's watching all of our files, and anytime one of them changes, 341 00:21:00,670 --> 00:21:04,230 it will run that associated test file. 342 00:21:04,230 --> 00:21:11,820 And maybe we don't want to have to run npm test --watch 343 00:21:11,820 --> 00:21:13,750 every single time we want to do that. 344 00:21:13,750 --> 00:21:17,340 We can just add another script to our package.json. 345 00:21:17,340 --> 00:21:24,597 So if I add a new script here that is test watch-- 346 00:21:24,597 --> 00:21:25,930 I can name this whatever I want. 347 00:21:25,930 --> 00:21:28,710 I'm just going to call it test watch. 348 00:21:28,710 --> 00:21:34,560 We can just run jest --watch. 349 00:21:34,560 --> 00:21:36,500 And it'll do that for me. 350 00:21:36,500 --> 00:21:42,670 And so you see here that we have jest with a single flag, --watch. 351 00:21:42,670 --> 00:21:46,710 The reason that we had to do two flags above like this was this 352 00:21:46,710 --> 00:21:51,550 would let us let NPM know that it should pass the next flag to whatever script 353 00:21:51,550 --> 00:21:52,860 it ends up running. 354 00:21:52,860 --> 00:21:57,600 But now we can just run npm run test watch. 355 00:21:57,600 --> 00:21:58,620 And it does that for us. 356 00:21:58,620 --> 00:22:02,621 357 00:22:02,621 --> 00:22:03,120 Great. 358 00:22:03,120 --> 00:22:06,290 So let's forge ahead and actually test some things 359 00:22:06,290 --> 00:22:10,390 that we've been using thus far. 360 00:22:10,390 --> 00:22:13,030 So let's go ahead and test our Redux actions. 361 00:22:13,030 --> 00:22:16,800 And so we can replace any of our tests that we 362 00:22:16,800 --> 00:22:20,970 have prior, which we don't have any yet, with expect to be and to equal. 363 00:22:20,970 --> 00:22:23,960 And so let's go ahead and write some tests for our Redux actions. 364 00:22:23,960 --> 00:22:28,580 365 00:22:28,580 --> 00:22:31,800 So rather than writing in a dummy sum file, 366 00:22:31,800 --> 00:22:38,060 let's actually open up our Redux, our actual actions, 367 00:22:38,060 --> 00:22:40,530 and start writing tests for these actions. 368 00:22:40,530 --> 00:22:42,650 And so if you remember from prior weeks, we 369 00:22:42,650 --> 00:22:47,210 have a couple action creators that are functions that take an update 370 00:22:47,210 --> 00:22:52,070 and return a type and a payload in the case of update user. 371 00:22:52,070 --> 00:22:54,710 In the case of add contact, it takes a new contact 372 00:22:54,710 --> 00:22:58,340 and returns an object or an action with a type and a payload. 373 00:22:58,340 --> 00:23:00,920 And then lastly, we have an async action creator 374 00:23:00,920 --> 00:23:03,900 that does a bunch of additional things. 375 00:23:03,900 --> 00:23:06,725 So let's go ahead and write a few tests for our action creators. 376 00:23:06,725 --> 00:23:09,600 377 00:23:09,600 --> 00:23:16,830 So let's first open actions.test.js file. 378 00:23:16,830 --> 00:23:20,650 And now let's write some tests for our Redux actions. 379 00:23:20,650 --> 00:23:22,940 And so what's the first one that we want to test? 380 00:23:22,940 --> 00:23:26,310 So let's just remember which exist. 381 00:23:26,310 --> 00:23:28,910 382 00:23:28,910 --> 00:23:34,010 So the first one we're going to test is the simple update user. 383 00:23:34,010 --> 00:23:38,874 And so let's go ahead and first import. 384 00:23:38,874 --> 00:23:40,415 Let's just import all of our actions. 385 00:23:40,415 --> 00:23:42,940 386 00:23:42,940 --> 00:23:49,550 So import everything as an object called actions from this file called actions. 387 00:23:49,550 --> 00:23:51,660 And then let's do some testing. 388 00:23:51,660 --> 00:24:06,327 So let's do test that update user returns the correct an action. 389 00:24:06,327 --> 00:24:07,660 And how are we going to do that? 390 00:24:07,660 --> 00:24:08,785 Well, it's just a function. 391 00:24:08,785 --> 00:24:12,960 392 00:24:12,960 --> 00:24:17,290 Let's invoke update user. 393 00:24:17,290 --> 00:24:26,260 So let's expect that if we invoke update user, and what are we going to pass? 394 00:24:26,260 --> 00:24:31,450 Let's just pass the name should be updated to test name. 395 00:24:31,450 --> 00:24:34,760 396 00:24:34,760 --> 00:24:36,440 And what do we expect that to be? 397 00:24:36,440 --> 00:24:47,300 Well, we expect it to be an object that has a type of actions.update user 398 00:24:47,300 --> 00:24:52,900 and a payload of name test name. 399 00:24:52,900 --> 00:24:58,590 400 00:24:58,590 --> 00:25:00,220 And we're missing parentheses there. 401 00:25:00,220 --> 00:25:10,890 402 00:25:10,890 --> 00:25:11,390 Great. 403 00:25:11,390 --> 00:25:13,580 So let's run this test and see what happens. 404 00:25:13,580 --> 00:25:21,440 405 00:25:21,440 --> 00:25:26,920 So if we run it, it will let us know something interesting. 406 00:25:26,920 --> 00:25:29,860 Well, one, the updateUser's not defined because it 407 00:25:29,860 --> 00:25:31,300 should be actions.update user. 408 00:25:31,300 --> 00:25:36,960 409 00:25:36,960 --> 00:25:39,690 So since we're importing all of the actions 410 00:25:39,690 --> 00:25:44,920 as an object called actions, if we want to use updateUser, 411 00:25:44,920 --> 00:25:48,360 we need to do actions.updateUser. 412 00:25:48,360 --> 00:25:54,000 And while we're at it, let's let ESLint know that there are 413 00:25:54,000 --> 00:25:58,800 a few globals called test and expect. 414 00:25:58,800 --> 00:26:03,860 415 00:26:03,860 --> 00:26:07,570 And now let's rerun those tests. 416 00:26:07,570 --> 00:26:10,110 And now it will tell us something interesting. 417 00:26:10,110 --> 00:26:21,810 It says we expected the value to be this object. 418 00:26:21,810 --> 00:26:24,650 And instead, we received this object. 419 00:26:24,650 --> 00:26:29,280 And you might notice that these two objects are exactly the same, character 420 00:26:29,280 --> 00:26:30,320 for character. 421 00:26:30,320 --> 00:26:33,880 And so why might it have errored? 422 00:26:33,880 --> 00:26:37,030 So if you remember back to an early lecture, 423 00:26:37,030 --> 00:26:39,150 we talked about how to compare objects. 424 00:26:39,150 --> 00:26:42,900 And the way if you compare objects with triple equals, what does it do? 425 00:26:42,900 --> 00:26:47,880 It doesn't compare the key value, all of those values within the object. 426 00:26:47,880 --> 00:26:50,610 It actually just checks if the two objects 427 00:26:50,610 --> 00:26:54,300 are being referenced in the same location 428 00:26:54,300 --> 00:27:00,930 because anything that is a non-primitive is stored via reference. 429 00:27:00,930 --> 00:27:08,010 And so since we created a new object in our .toBe in our test file, we see, oh, 430 00:27:08,010 --> 00:27:09,860 object is equality. 431 00:27:09,860 --> 00:27:12,600 They're not referencing the exact same object. 432 00:27:12,600 --> 00:27:14,640 And it actually lets us know, hey, the compared 433 00:27:14,640 --> 00:27:16,850 values have no visual difference, meaning 434 00:27:16,850 --> 00:27:19,110 they're basically the same object here. 435 00:27:19,110 --> 00:27:22,680 Looks like you probably wanted to test for the object array 436 00:27:22,680 --> 00:27:25,620 equality, which is-- 437 00:27:25,620 --> 00:27:30,060 we should probably use toEqual, which actually does that check 438 00:27:30,060 --> 00:27:32,220 and will check the key-value pairs rather 439 00:27:32,220 --> 00:27:33,700 than just checking the reference. 440 00:27:33,700 --> 00:27:37,620 And so let's go ahead and update our code so that it's actually correctly 441 00:27:37,620 --> 00:27:41,010 checking what we want it to check. 442 00:27:41,010 --> 00:27:44,640 So let's now do actions.test.js. 443 00:27:44,640 --> 00:27:48,540 And rather than using .toBe here, let's use toEqual. 444 00:27:48,540 --> 00:27:52,640 445 00:27:52,640 --> 00:27:57,700 And now let's run npm test. 446 00:27:57,700 --> 00:28:02,530 And we should see that now it actually does indeed pass. 447 00:28:02,530 --> 00:28:06,280 448 00:28:06,280 --> 00:28:06,780 Great. 449 00:28:06,780 --> 00:28:09,010 So let's add a few more tests. 450 00:28:09,010 --> 00:28:14,520 451 00:28:14,520 --> 00:28:27,389 Maybe let's pass a different name here. 452 00:28:27,389 --> 00:28:28,805 Maybe we'll update a phone number. 453 00:28:28,805 --> 00:28:33,130 454 00:28:33,130 --> 00:28:36,940 And let's make it some bogus phone number. 455 00:28:36,940 --> 00:28:42,040 And then we want to change the payload here to be that phone. 456 00:28:42,040 --> 00:28:46,970 457 00:28:46,970 --> 00:28:49,970 And what do you notice that I'm doing right here? 458 00:28:49,970 --> 00:28:56,450 It's interesting because I'm almost reimplementing this action, right? 459 00:28:56,450 --> 00:29:04,000 My test is basically the exact same logic as the actual actions file. 460 00:29:04,000 --> 00:29:06,760 461 00:29:06,760 --> 00:29:16,140 Because our updateUser takes an update and returns 462 00:29:16,140 --> 00:29:18,480 an object with that type and payload. 463 00:29:18,480 --> 00:29:21,180 And down here, we're doing almost the exact same thing. 464 00:29:21,180 --> 00:29:27,030 We're doing an action with this and checking against an object 465 00:29:27,030 --> 00:29:28,190 with a type and a payload. 466 00:29:28,190 --> 00:29:35,970 And so we're almost word for word just reimplementing that exact function, 467 00:29:35,970 --> 00:29:38,410 which isn't really great in terms of testing 468 00:29:38,410 --> 00:29:42,510 because if we're testing a function by running a function 469 00:29:42,510 --> 00:29:44,725 that we implemented in the exact same way, 470 00:29:44,725 --> 00:29:47,100 if there's a bug in the first function, of course there's 471 00:29:47,100 --> 00:29:49,440 going to be a bug in the test function. 472 00:29:49,440 --> 00:29:54,400 And so we won't actually catch any bugs that we might have intended to catch. 473 00:29:54,400 --> 00:29:59,470 And so what might be a better way to test this? 474 00:29:59,470 --> 00:30:01,950 Well, it turns out there's this thing called snapshots, 475 00:30:01,950 --> 00:30:09,184 which compares an output of a function in the past to what we get now, 476 00:30:09,184 --> 00:30:11,850 which is good because now we get notified if the output changes, 477 00:30:11,850 --> 00:30:16,080 which is really what we want when we test these action creators. 478 00:30:16,080 --> 00:30:19,227 Because since they're really simple and just returning a new object, 479 00:30:19,227 --> 00:30:22,310 we just want to make sure that it's returning what we expect it to return. 480 00:30:22,310 --> 00:30:27,480 And so then if we end up changing something later, 481 00:30:27,480 --> 00:30:30,270 we get notified that something changes, but we don't actually 482 00:30:30,270 --> 00:30:33,610 have to rewrite the test if that change was actually intended. 483 00:30:33,610 --> 00:30:36,900 And so let's actually refactor our test to rather than 484 00:30:36,900 --> 00:30:41,730 mirroring the logic in our actions, to, rather, use a snapshot. 485 00:30:41,730 --> 00:30:46,620 486 00:30:46,620 --> 00:30:50,130 So currently, we're doing expect this to equal, 487 00:30:50,130 --> 00:30:53,070 and then hard coding exactly what we know is going to come out. 488 00:30:53,070 --> 00:30:57,945 But maybe instead, we should do toMatch the snapshot. 489 00:30:57,945 --> 00:31:00,500 490 00:31:00,500 --> 00:31:02,000 And we can go ahead and delete that. 491 00:31:02,000 --> 00:31:05,300 492 00:31:05,300 --> 00:31:15,780 And so if we now save that and run npm test, 493 00:31:15,780 --> 00:31:19,210 we see that the snapshot was saved. 494 00:31:19,210 --> 00:31:24,210 And now let's change it to see if the snapshot-- 495 00:31:24,210 --> 00:31:25,570 if we're notified, as expected. 496 00:31:25,570 --> 00:31:29,720 497 00:31:29,720 --> 00:31:34,780 So let's change our actions file. 498 00:31:34,780 --> 00:31:41,170 And maybe we'll send a type that's updateUser, a payload that's update, 499 00:31:41,170 --> 00:31:43,002 and also-- 500 00:31:43,002 --> 00:31:44,710 we wouldn't want to do this in real life. 501 00:31:44,710 --> 00:31:52,840 But maybe we'll just add a debug flag that says false. 502 00:31:52,840 --> 00:31:56,980 So something completely useless, but it is in fact changing our implementation. 503 00:31:56,980 --> 00:32:02,060 And so now if we run npm test, we'll see, uh-oh. 504 00:32:02,060 --> 00:32:03,941 One of our snapshot tests failed. 505 00:32:03,941 --> 00:32:04,940 Let's see what happened. 506 00:32:04,940 --> 00:32:08,180 507 00:32:08,180 --> 00:32:11,400 In our actions.test.js, we see that update in our test 508 00:32:11,400 --> 00:32:14,580 called updateUser returns an action. 509 00:32:14,580 --> 00:32:18,520 We see that the received value does not match the stored snapshot. 510 00:32:18,520 --> 00:32:21,510 And it'll actually tell us exactly what changed. 511 00:32:21,510 --> 00:32:27,324 It says that the snapshot received something new. 512 00:32:27,324 --> 00:32:28,740 That's what this plus received is. 513 00:32:28,740 --> 00:32:31,230 And what it received that was new was this debug false, 514 00:32:31,230 --> 00:32:35,305 which wasn't in the original snapshot, which is great because maybe we 515 00:32:35,305 --> 00:32:36,430 didn't want to change that. 516 00:32:36,430 --> 00:32:38,180 It's just letting us know that it changed. 517 00:32:38,180 --> 00:32:44,070 And so how do we let Jest know, hey, we meant for that to happen? 518 00:32:44,070 --> 00:32:46,350 Update your snapshot. 519 00:32:46,350 --> 00:32:50,850 Well, it tells us inspect your changes or run npm test -- 520 00:32:50,850 --> 00:32:52,600 -u to update it. 521 00:32:52,600 --> 00:32:59,310 And so we can just run npm test -- 522 00:32:59,310 --> 00:33:00,245 -u. 523 00:33:00,245 --> 00:33:05,535 And it will go ahead and update the snapshot in our test suite. 524 00:33:05,535 --> 00:33:07,415 And so let's go ahead and revert our change. 525 00:33:07,415 --> 00:33:13,910 526 00:33:13,910 --> 00:33:17,116 And now again, if we test, what do we expect to happen? 527 00:33:17,116 --> 00:33:18,240 Well, we changed something. 528 00:33:18,240 --> 00:33:20,780 So the snapshot test should fail. 529 00:33:20,780 --> 00:33:26,150 If we go read what failed, it says, oh, now this is minus. 530 00:33:26,150 --> 00:33:26,770 It's gone. 531 00:33:26,770 --> 00:33:29,180 And we expected it to be there. 532 00:33:29,180 --> 00:33:33,510 We can that Jest know, oh, by the way, we meant for that to happen. 533 00:33:33,510 --> 00:33:34,430 So -u. 534 00:33:34,430 --> 00:33:36,860 Update your snapshots accordingly. 535 00:33:36,860 --> 00:33:39,380 And now if we run npm test after updating, 536 00:33:39,380 --> 00:33:41,420 everything passes, and all is good in the world. 537 00:33:41,420 --> 00:33:45,630 538 00:33:45,630 --> 00:33:46,130 Great. 539 00:33:46,130 --> 00:33:48,297 So now let's add a few more tests just to make 540 00:33:48,297 --> 00:33:49,880 sure everything's working as expected. 541 00:33:49,880 --> 00:34:00,440 542 00:34:00,440 --> 00:34:11,330 And so maybe we want to test the case where updateUser returns an action when 543 00:34:11,330 --> 00:34:12,760 passed empty object. 544 00:34:12,760 --> 00:34:21,832 545 00:34:21,832 --> 00:34:23,290 And we can just cut and paste this. 546 00:34:23,290 --> 00:34:26,389 547 00:34:26,389 --> 00:34:31,250 And rather than passing an object here, we can just pass an empty object. 548 00:34:31,250 --> 00:34:34,250 And we expect it to match whatever the snapshot was. 549 00:34:34,250 --> 00:34:45,829 And so maybe we also want to test a case where you pass an empty name. 550 00:34:45,829 --> 00:34:49,850 And so let's do name is empty. 551 00:34:49,850 --> 00:34:53,630 And so now you're starting to see a bunch of very similar tests. 552 00:34:53,630 --> 00:34:56,520 And maybe there's a better way to go ahead and group them together. 553 00:34:56,520 --> 00:34:57,603 And it turns out there is. 554 00:34:57,603 --> 00:35:02,450 You can describe a group of actions, and Jest 555 00:35:02,450 --> 00:35:04,340 will automatically group them for you. 556 00:35:04,340 --> 00:35:07,220 And so the way to do that is-- 557 00:35:07,220 --> 00:35:08,870 let's first look at the output of this. 558 00:35:08,870 --> 00:35:13,150 559 00:35:13,150 --> 00:35:17,290 It just lets us know that some tests are passing. 560 00:35:17,290 --> 00:35:20,660 But maybe let's add a logical group of tests together. 561 00:35:20,660 --> 00:35:26,030 So let's do actions.test.js and group these very similar tests together. 562 00:35:26,030 --> 00:35:30,400 And so now let's describe a group of tests. 563 00:35:30,400 --> 00:35:36,025 And so this one is updateUser returns actions. 564 00:35:36,025 --> 00:35:38,530 565 00:35:38,530 --> 00:35:42,040 And it takes a callback, just like the other tests. 566 00:35:42,040 --> 00:35:49,060 567 00:35:49,060 --> 00:35:50,950 And now we can group these things together. 568 00:35:50,950 --> 00:35:54,040 And rather than using test, we do it. 569 00:35:54,040 --> 00:35:56,860 570 00:35:56,860 --> 00:35:57,880 And what does it do? 571 00:35:57,880 --> 00:36:13,140 It returns an action, or it handles an empty object 572 00:36:13,140 --> 00:36:20,450 or it handles an empty name. 573 00:36:20,450 --> 00:36:25,880 574 00:36:25,880 --> 00:36:30,740 And now if we run these tests, we see that there-- 575 00:36:30,740 --> 00:36:34,830 well, they have obsolete snapshots because we updated the tests. 576 00:36:34,830 --> 00:36:38,840 So we'll go ahead and first update all of these things. 577 00:36:38,840 --> 00:36:49,560 578 00:36:49,560 --> 00:36:51,845 And now it works. 579 00:36:51,845 --> 00:36:57,420 580 00:36:57,420 --> 00:36:59,650 But it's not giving me the pretty output. 581 00:36:59,650 --> 00:37:02,925 Let me see why not. 582 00:37:02,925 --> 00:37:07,020 Oh, we should run our watch mode. 583 00:37:07,020 --> 00:37:21,690 584 00:37:21,690 --> 00:37:22,190 Hmm. 585 00:37:22,190 --> 00:37:24,910 It's not giving us the pretty output. 586 00:37:24,910 --> 00:37:27,320 And I will look into it at the break. 587 00:37:27,320 --> 00:37:34,170 But this is a way of joining very similar tests 588 00:37:34,170 --> 00:37:36,370 together in logical groups. 589 00:37:36,370 --> 00:37:43,600 And we should let ESLint know that we added a few more globally available 590 00:37:43,600 --> 00:37:47,240 variables, including describe and it. 591 00:37:47,240 --> 00:38:01,650 592 00:38:01,650 --> 00:38:03,540 Great. 593 00:38:03,540 --> 00:38:10,050 So now let's take a look at trying to test a more complicated action. 594 00:38:10,050 --> 00:38:20,690 So what happens if we want to test this async action that we wrote? 595 00:38:20,690 --> 00:38:23,280 It's a lot more complicated than the simple actions 596 00:38:23,280 --> 00:38:27,660 that just took a single argument and immediately returned a new object. 597 00:38:27,660 --> 00:38:31,060 This one's doing a few different other things. 598 00:38:31,060 --> 00:38:33,300 And so how might we go ahead and do this? 599 00:38:33,300 --> 00:38:34,740 Well, one, it's async. 600 00:38:34,740 --> 00:38:38,250 So that might be a bit of a difficulty. 601 00:38:38,250 --> 00:38:40,810 So it turns out-- 602 00:38:40,810 --> 00:38:45,219 oh, so which of these functions should we use? 603 00:38:45,219 --> 00:38:47,260 If you're using primitives, then you can use toBe 604 00:38:47,260 --> 00:38:50,429 because as we learned in an earlier lecture, 605 00:38:50,429 --> 00:38:52,470 you can just check primitives with triple equals. 606 00:38:52,470 --> 00:38:56,280 And it'll go ahead and see if those values are equivalent. 607 00:38:56,280 --> 00:39:00,060 If you're doing objects and you don't expect those objects to ever change, 608 00:39:00,060 --> 00:39:03,870 you might want to use toEqual like we did in the earlier example 609 00:39:03,870 --> 00:39:07,320 because it will do a deeper equality check. 610 00:39:07,320 --> 00:39:10,440 But that has the downside that it will actually error 611 00:39:10,440 --> 00:39:12,160 if we end up changing the objects. 612 00:39:12,160 --> 00:39:15,060 And we'll have to go back and rewrite those tests. 613 00:39:15,060 --> 00:39:17,760 If we have objects that might change in the future, 614 00:39:17,760 --> 00:39:19,920 that's when we should use something like a snapshot 615 00:39:19,920 --> 00:39:23,250 because then it will give us the benefits of knowing 616 00:39:23,250 --> 00:39:25,680 that we changed our function. 617 00:39:25,680 --> 00:39:29,414 But if that was a change that we were OK with or a change that we intended, 618 00:39:29,414 --> 00:39:31,830 then we don't have to go back and rewrite all of our tests 619 00:39:31,830 --> 00:39:33,871 like we would have if we were using that toEqual. 620 00:39:33,871 --> 00:39:36,540 621 00:39:36,540 --> 00:39:40,815 So now let's take a look at some asynchronous actions. 622 00:39:40,815 --> 00:39:44,970 And so why might this be more difficult? 623 00:39:44,970 --> 00:39:48,270 Well, it adds a few different difficulties, it seems. 624 00:39:48,270 --> 00:39:50,580 So we have to wait for the results to come back 625 00:39:50,580 --> 00:39:52,740 before we check against the results. 626 00:39:52,740 --> 00:39:55,350 So that might be a little bit tricky. 627 00:39:55,350 --> 00:39:59,460 Our tests also might rely on libraries, other libraries that we go ahead 628 00:39:59,460 --> 00:40:01,080 and import. 629 00:40:01,080 --> 00:40:03,570 And lastly, what about external services? 630 00:40:03,570 --> 00:40:09,420 And so in our login user, we're actually awaiting 631 00:40:09,420 --> 00:40:12,510 login, which sends a fetch request to an external service. 632 00:40:12,510 --> 00:40:15,070 633 00:40:15,070 --> 00:40:19,230 So how might we go ahead and combat these three difficulties? 634 00:40:19,230 --> 00:40:21,740 Well, for the first one, if we return a promise, 635 00:40:21,740 --> 00:40:24,870 Jest is smart enough to be able to wait for it to resolve 636 00:40:24,870 --> 00:40:29,620 before it checks against that value. 637 00:40:29,620 --> 00:40:32,230 Jest also supports async await, which is awesome 638 00:40:32,230 --> 00:40:37,000 because we can just await a value, and then go and check against it. 639 00:40:37,000 --> 00:40:44,140 And so let's go ahead and start to write a test for this asynchronous action 640 00:40:44,140 --> 00:40:45,410 created here. 641 00:40:45,410 --> 00:41:08,940 And so we're going to be using logInUser 642 00:41:08,940 --> 00:41:12,376 And let's describe a group of tests to see if logInUser 643 00:41:12,376 --> 00:41:14,000 returns the actions that we want it to. 644 00:41:14,000 --> 00:41:21,390 645 00:41:21,390 --> 00:41:25,440 So first, logInUser should do what? 646 00:41:25,440 --> 00:41:37,130 It should dispatch an action that the login is sent. 647 00:41:37,130 --> 00:41:41,250 Then it's going to try to do something by awaiting a login. 648 00:41:41,250 --> 00:41:44,560 And then it's going to dispatch something else. 649 00:41:44,560 --> 00:41:46,980 And then if there's an error anywhere up there, 650 00:41:46,980 --> 00:41:50,070 it's going to dispatch something else again. 651 00:41:50,070 --> 00:41:55,870 And so it might be a little bit difficult to track what's going on. 652 00:41:55,870 --> 00:41:59,234 So let's first just write some dummy function dispatch 653 00:41:59,234 --> 00:42:00,650 that doesn't actually do anything. 654 00:42:00,650 --> 00:42:12,250 655 00:42:12,250 --> 00:42:18,320 Then, if we wanted, we could await logInUser. 656 00:42:18,320 --> 00:42:19,600 But what happens then? 657 00:42:19,600 --> 00:42:30,250 If we run this, we'll see that-- 658 00:42:30,250 --> 00:42:30,750 uh-oh. 659 00:42:30,750 --> 00:42:32,820 Await is a reserved word. 660 00:42:32,820 --> 00:42:36,420 So what do we have to do if we're ever going to use that await key word? 661 00:42:36,420 --> 00:42:39,920 662 00:42:39,920 --> 00:42:45,691 Well, first we need to make sure to let JavaScript know that hey, 663 00:42:45,691 --> 00:42:46,940 this is not a normal function. 664 00:42:46,940 --> 00:42:48,023 This is an async function. 665 00:42:48,023 --> 00:42:50,580 666 00:42:50,580 --> 00:42:54,660 And so now we can invoke logInUser with whatever we want-- 667 00:42:54,660 --> 00:42:58,490 so the user name and password-- 668 00:42:58,490 --> 00:43:00,200 and then also pass it dispatch. 669 00:43:00,200 --> 00:43:08,910 670 00:43:08,910 --> 00:43:12,090 And then we expect it to error here. 671 00:43:12,090 --> 00:43:16,680 And I'm just going to wave my hand at that case for now. 672 00:43:16,680 --> 00:43:23,190 673 00:43:23,190 --> 00:43:27,230 So right now, for this function called dispatch, 674 00:43:27,230 --> 00:43:28,980 we don't really know what to do with this. 675 00:43:28,980 --> 00:43:33,330 In our actual application, what happens in this particular action? 676 00:43:33,330 --> 00:43:36,580 Well, we have that Redux [? flunk ?] middleware, 677 00:43:36,580 --> 00:43:39,450 which handles passing that dispatch function in for us 678 00:43:39,450 --> 00:43:42,960 and will dispatch those actions to the store on our behalf. 679 00:43:42,960 --> 00:43:47,910 But in our particular unit test here, we don't really have access to that store. 680 00:43:47,910 --> 00:43:50,880 We don't want to rely on these external libraries 681 00:43:50,880 --> 00:43:58,314 in order to run this code here, which is that second difficulty here. 682 00:43:58,314 --> 00:43:59,730 And so how might we go about that? 683 00:43:59,730 --> 00:44:01,710 Right now, we just wrote a dummy function. 684 00:44:01,710 --> 00:44:05,710 But certainly there's a better way to do this. 685 00:44:05,710 --> 00:44:09,960 Well, it turns out Jest supports doing what are called mock functions, which 686 00:44:09,960 --> 00:44:13,410 is similar to what we're doing, but these mock functions actually 687 00:44:13,410 --> 00:44:14,080 do something. 688 00:44:14,080 --> 00:44:18,360 They will track what they're invoked with or invoked on. 689 00:44:18,360 --> 00:44:22,230 And so we can actually use this mock to be 690 00:44:22,230 --> 00:44:28,020 able to figure out exactly what actions are being dispatched because if you 691 00:44:28,020 --> 00:44:33,900 remember the way that this action works, first it'll 692 00:44:33,900 --> 00:44:39,150 dispatch an action that's letting the Redux store know that we 693 00:44:39,150 --> 00:44:41,677 have sent off this login request. 694 00:44:41,677 --> 00:44:43,260 Then it's going to go ahead and do it. 695 00:44:43,260 --> 00:44:46,890 And depending on what happens, it's going to dispatch other actions. 696 00:44:46,890 --> 00:44:49,110 And so if we mock this dispatch function, 697 00:44:49,110 --> 00:44:55,890 we can go ahead and check exactly what values the dispatch is invoked with. 698 00:44:55,890 --> 00:44:57,040 So how might we do that? 699 00:44:57,040 --> 00:45:05,130 700 00:45:05,130 --> 00:45:11,300 So rather than-- oh, this should be actions.logInUser. 701 00:45:11,300 --> 00:45:17,650 Rather than just writing dispatch as a dummy function that we wrote here, 702 00:45:17,650 --> 00:45:19,580 let's actually use jest.function-- 703 00:45:19,580 --> 00:45:23,465 704 00:45:23,465 --> 00:45:29,270 .fn, I believe-- which creates one of those Jest mock functions. 705 00:45:29,270 --> 00:45:35,290 And so now we can go ahead and use that to track exactly what happens. 706 00:45:35,290 --> 00:45:45,000 So let's do it. 707 00:45:45,000 --> 00:45:49,510 708 00:45:49,510 --> 00:46:02,710 So let's test that it dispatches the login sent action correctly. 709 00:46:02,710 --> 00:46:05,550 And how are we going to test for that? 710 00:46:05,550 --> 00:46:09,140 Well, first we're going to create that dummy function, 711 00:46:09,140 --> 00:46:13,880 that mock function by Jest. 712 00:46:13,880 --> 00:46:19,930 Then let's go ahead and kick off the action here. 713 00:46:19,930 --> 00:46:25,710 And so let's just write mockDispatch so that we can remember what that is. 714 00:46:25,710 --> 00:46:30,111 715 00:46:30,111 --> 00:46:30,610 So great. 716 00:46:30,610 --> 00:46:32,460 We created a mock dispatch function. 717 00:46:32,460 --> 00:46:41,910 We go ahead and pass it in as the mock dispatch in our login actions. 718 00:46:41,910 --> 00:46:45,610 And how are we going to check to see exactly what happened? 719 00:46:45,610 --> 00:46:49,980 Well, it turns out attached to mock dispatch, we can see all of the things 720 00:46:49,980 --> 00:46:51,660 that it was invoked on. 721 00:46:51,660 --> 00:46:53,490 So first let me fix this. 722 00:46:53,490 --> 00:46:55,589 This should be an async function. 723 00:46:55,589 --> 00:46:57,630 And this no longer needs to be an async function. 724 00:46:57,630 --> 00:47:00,160 725 00:47:00,160 --> 00:47:08,160 So how might we want to check to see what the mock dispatch was called on? 726 00:47:08,160 --> 00:47:11,490 Well, it turns out we can check. 727 00:47:11,490 --> 00:47:13,080 We can see mockDispatch-- 728 00:47:13,080 --> 00:47:16,080 729 00:47:16,080 --> 00:47:18,930 let me check the documentation really quick-- 730 00:47:18,930 --> 00:47:22,450 .mock.calls. 731 00:47:22,450 --> 00:47:28,720 And what that does is it's all of the calls 732 00:47:28,720 --> 00:47:31,420 that the mock function was invoked on. 733 00:47:31,420 --> 00:47:38,150 734 00:47:38,150 --> 00:47:40,640 So that's really helpful. 735 00:47:40,640 --> 00:47:41,850 Why is that helpful? 736 00:47:41,850 --> 00:47:45,290 Well, we can just see if that dispatch was invoked with the action 737 00:47:45,290 --> 00:47:47,805 that we were expecting it to be invoked with. 738 00:47:47,805 --> 00:47:49,430 So let's just console log that for now. 739 00:47:49,430 --> 00:47:59,880 740 00:47:59,880 --> 00:48:04,855 And let's also let ESLint know that jest is globally available. 741 00:48:04,855 --> 00:48:19,330 742 00:48:19,330 --> 00:48:20,480 So now let's run npm test. 743 00:48:20,480 --> 00:48:24,917 744 00:48:24,917 --> 00:48:26,820 And we see what? 745 00:48:26,820 --> 00:48:30,250 We see that login was sent, which is great. 746 00:48:30,250 --> 00:48:33,600 We expected dispatch to be invoked with login sent. 747 00:48:33,600 --> 00:48:37,350 And then we also see that login is then later rejected because fetch is not 748 00:48:37,350 --> 00:48:40,290 defined, which is a problem. 749 00:48:40,290 --> 00:48:43,170 But for now, we're only focusing on whether or not 750 00:48:43,170 --> 00:48:46,510 the login sent was done successfully. 751 00:48:46,510 --> 00:48:52,310 So let's finish that test to actually check for that. 752 00:48:52,310 --> 00:48:58,530 753 00:48:58,530 --> 00:49:02,610 So rather than console.logging the mockDispatch.mock.calls, 754 00:49:02,610 --> 00:49:05,380 we can actually expect it to be some value. 755 00:49:05,380 --> 00:49:07,660 So let's expect mockDispatch.mock.calls. 756 00:49:07,660 --> 00:49:11,160 757 00:49:11,160 --> 00:49:14,470 We should probably look at the first time it was called, 758 00:49:14,470 --> 00:49:17,910 which is indexing into that first array. 759 00:49:17,910 --> 00:49:21,780 And let's also look at the first value or the first argument 760 00:49:21,780 --> 00:49:23,050 that it was invoked with. 761 00:49:23,050 --> 00:49:26,914 And so let's index into that. 762 00:49:26,914 --> 00:49:28,580 And we expect it to be something, right? 763 00:49:28,580 --> 00:49:38,660 We expect it to be an object that has a login sent value as the type. 764 00:49:38,660 --> 00:49:48,030 765 00:49:48,030 --> 00:49:50,010 And what's going to happen when we run this? 766 00:49:50,010 --> 00:49:51,400 Does anybody know? 767 00:49:51,400 --> 00:50:01,480 768 00:50:01,480 --> 00:50:04,090 We get that same error that we got earlier. 769 00:50:04,090 --> 00:50:07,160 We see that these two objects are the same. 770 00:50:07,160 --> 00:50:09,190 771 00:50:09,190 --> 00:50:11,590 But the test is still failing. 772 00:50:11,590 --> 00:50:14,560 And it's the same reason why it failed earlier. 773 00:50:14,560 --> 00:50:17,260 The two values have no visual difference, 774 00:50:17,260 --> 00:50:19,660 but we are checking their reference. 775 00:50:19,660 --> 00:50:23,290 And since we just created that second object, 776 00:50:23,290 --> 00:50:27,500 obviously those references aren't going to match. 777 00:50:27,500 --> 00:50:29,875 And so rather than using toBe, what should we do instead? 778 00:50:29,875 --> 00:50:33,879 779 00:50:33,879 --> 00:50:35,670 Well, we should probably use that .toEqual. 780 00:50:35,670 --> 00:50:48,060 781 00:50:48,060 --> 00:50:50,880 And now we see that those do, in fact, pass. 782 00:50:50,880 --> 00:50:53,400 783 00:50:53,400 --> 00:50:54,720 Great. 784 00:50:54,720 --> 00:50:57,270 But that wasn't really the difficult part, right? 785 00:50:57,270 --> 00:51:00,870 It's pretty easy to see in our code that that's exactly what's going to happen. 786 00:51:00,870 --> 00:51:05,670 787 00:51:05,670 --> 00:51:13,920 Really, the hard part is to make sure that this does what we expect it to do. 788 00:51:13,920 --> 00:51:19,410 But since login is defined within the logInUser, 789 00:51:19,410 --> 00:51:23,040 that means we have to rely on that to work. 790 00:51:23,040 --> 00:51:25,950 And we don't really want our unit tests to rely 791 00:51:25,950 --> 00:51:28,470 on things that are way outside our control, in this case 792 00:51:28,470 --> 00:51:33,600 an API network request that's being sent out. 793 00:51:33,600 --> 00:51:36,690 So how might we get around that problem? 794 00:51:36,690 --> 00:51:41,380 It's actually not an easy one to solve. 795 00:51:41,380 --> 00:51:45,330 There's actually a strategy called dependency injection, 796 00:51:45,330 --> 00:51:49,426 which we can go ahead and use to get around this problem. 797 00:51:49,426 --> 00:51:52,830 And so what dependency injection is is that we 798 00:51:52,830 --> 00:51:55,200 pass functions on which other functions rely 799 00:51:55,200 --> 00:51:58,710 on as arguments to those functions. 800 00:51:58,710 --> 00:52:01,630 So we make these functions even more [? pure. ?] 801 00:52:01,630 --> 00:52:06,300 And so everything that they need, they receive as arguments. 802 00:52:06,300 --> 00:52:07,480 And how does that help us? 803 00:52:07,480 --> 00:52:13,110 Well, it allows us to mock the functions that rely on external services, which 804 00:52:13,110 --> 00:52:14,710 is pretty nifty. 805 00:52:14,710 --> 00:52:18,660 So rather than using login here, we can make 806 00:52:18,660 --> 00:52:26,370 this [? pure ?] by taking the login function 807 00:52:26,370 --> 00:52:32,080 as an argument in our logInUser. 808 00:52:32,080 --> 00:52:33,670 But what did we just do? 809 00:52:33,670 --> 00:52:37,920 We changed the-- well, we didn't actually change anything yet. 810 00:52:37,920 --> 00:52:41,610 If we use it here, now we've gone and changed 811 00:52:41,610 --> 00:52:46,470 the way that you're supposed to use the logInUser function, which 812 00:52:46,470 --> 00:52:50,250 means we broke backwards compatibility, which means every single time we use 813 00:52:50,250 --> 00:52:55,030 this logInUser function in our entire app, we now have to go and fix, 814 00:52:55,030 --> 00:52:58,680 which is not really fun. 815 00:52:58,680 --> 00:53:02,290 So how might we get around that? 816 00:53:02,290 --> 00:53:06,200 So what happens every time, currently in our app, we want to use logInUser? 817 00:53:06,200 --> 00:53:11,310 Right now, we pass two arguments, username and password. 818 00:53:11,310 --> 00:53:15,990 And in no places do we pass a third argument 819 00:53:15,990 --> 00:53:18,910 because we weren't supposed to. 820 00:53:18,910 --> 00:53:22,350 And so if we know that we're never going to pass a third argument, 821 00:53:22,350 --> 00:53:26,926 we can have some sort of default argument that it falls back on. 822 00:53:26,926 --> 00:53:28,800 And so one thing that we could do is we could 823 00:53:28,800 --> 00:53:39,110 do const login or const realLoginFn is either 824 00:53:39,110 --> 00:53:42,700 the login function if it's passed-- 825 00:53:42,700 --> 00:53:45,090 so if so. 826 00:53:45,090 --> 00:53:54,540 Otherwise, the login that we imported at the top of the file here. 827 00:53:54,540 --> 00:54:01,920 Or if we want to use some more shorthand, we can do login or login. 828 00:54:01,920 --> 00:54:08,050 Or we can rely on a JavaScript feature called default function values. 829 00:54:08,050 --> 00:54:13,440 So if nothing is passed as the argument, a third argument here, 830 00:54:13,440 --> 00:54:20,910 we can have a default value be login, which 831 00:54:20,910 --> 00:54:25,020 means expect to get a username and a password in the login function. 832 00:54:25,020 --> 00:54:29,250 And if you receive undefined for this third value, 833 00:54:29,250 --> 00:54:31,650 then use this default value instead. 834 00:54:31,650 --> 00:54:35,010 835 00:54:35,010 --> 00:54:40,530 And now we've added dependency injection, 836 00:54:40,530 --> 00:54:47,220 but we haven't actually changed our logInUser function. 837 00:54:47,220 --> 00:54:53,220 Because everywhere that we use it in our app, we pass two arguments. 838 00:54:53,220 --> 00:54:55,140 And this login function will always fall back 839 00:54:55,140 --> 00:55:00,870 to the default, which is the login function which we imported up here. 840 00:55:00,870 --> 00:55:03,700 And so that will always be used here. 841 00:55:03,700 --> 00:55:05,850 And so it does exactly what it did before. 842 00:55:05,850 --> 00:55:14,140 But now in our tests, we can go ahead and add a mock function for login. 843 00:55:14,140 --> 00:55:15,390 So let's go ahead and do that. 844 00:55:15,390 --> 00:55:24,540 845 00:55:24,540 --> 00:55:30,020 So now we have a test.test to see if it dispatches login sent. 846 00:55:30,020 --> 00:55:43,920 We can add now a test with correct credentials. 847 00:55:43,920 --> 00:55:50,380 848 00:55:50,380 --> 00:55:54,520 So now let's make sure that if we pass the correct credentials, we get in. 849 00:55:54,520 --> 00:55:58,150 We get the login fulfilled. 850 00:55:58,150 --> 00:56:01,209 So how are we going to do that? 851 00:56:01,209 --> 00:56:03,125 Well, we should probably have a mock dispatch. 852 00:56:03,125 --> 00:56:06,880 853 00:56:06,880 --> 00:56:09,940 But we need another mock function. 854 00:56:09,940 --> 00:56:11,890 Or do we? 855 00:56:11,890 --> 00:56:15,070 So the special thing about the Jest mock functions 856 00:56:15,070 --> 00:56:20,697 here is that they can track whatever they were passed in. 857 00:56:20,697 --> 00:56:22,030 And we can reference that later. 858 00:56:22,030 --> 00:56:26,110 But does that really help us in our logInUser example? 859 00:56:26,110 --> 00:56:28,810 Let's check back to see what happened here. 860 00:56:28,810 --> 00:56:31,340 861 00:56:31,340 --> 00:56:37,000 So for our login function down here, all that we're doing 862 00:56:37,000 --> 00:56:40,120 is we're extracting a token from it. 863 00:56:40,120 --> 00:56:47,250 And so either it works and we receive a token, or it doesn't work, 864 00:56:47,250 --> 00:56:52,570 and supposedly an error is thrown, which we then catch down here. 865 00:56:52,570 --> 00:56:58,300 And so we don't really need to mock a function using Jest here 866 00:56:58,300 --> 00:57:02,110 because we don't really care what username and password were passed in. 867 00:57:02,110 --> 00:57:04,870 And we don't care about the history going back. 868 00:57:04,870 --> 00:57:10,000 We really only care about whether this login function returns a token, 869 00:57:10,000 --> 00:57:11,395 or whether it throws an error. 870 00:57:11,395 --> 00:57:19,125 And so rather than using the jest.function, 871 00:57:19,125 --> 00:57:20,750 we don't need to use the mock function. 872 00:57:20,750 --> 00:57:24,560 Instead, we can actually just define a function ourselves. 873 00:57:24,560 --> 00:57:26,090 And so let's do that. 874 00:57:26,090 --> 00:57:38,160 Let's do const login is a function that takes a username and a password. 875 00:57:38,160 --> 00:57:38,910 And what happens? 876 00:57:38,910 --> 00:57:46,610 877 00:57:46,610 --> 00:57:54,800 So if the username is username, or we can just-- 878 00:57:54,800 --> 00:57:56,360 do whatever we want. 879 00:57:56,360 --> 00:58:05,930 We can say if the user name is u and the password 880 00:58:05,930 --> 00:58:10,070 is p, then what do we want to do? 881 00:58:10,070 --> 00:58:14,110 We want to return a token. 882 00:58:14,110 --> 00:58:17,170 So this is a test token. 883 00:58:17,170 --> 00:58:20,500 884 00:58:20,500 --> 00:58:22,367 Otherwise, what do you want to do? 885 00:58:22,367 --> 00:58:23,950 Well, it should throw an error, right? 886 00:58:23,950 --> 00:58:26,140 So we can throw new error. 887 00:58:26,140 --> 00:58:29,830 888 00:58:29,830 --> 00:58:34,330 Incorrect credentials. 889 00:58:34,330 --> 00:58:38,740 890 00:58:38,740 --> 00:58:40,120 So let's clean this up. 891 00:58:40,120 --> 00:58:53,350 892 00:58:53,350 --> 00:58:55,830 So now we have a mock dispatch function. 893 00:58:55,830 --> 00:58:59,940 And we also have now a mock login function. 894 00:58:59,940 --> 00:59:02,940 And when I say mock, it's not actually a Jest mock function. 895 00:59:02,940 --> 00:59:05,910 It's just a function that we defined. 896 00:59:05,910 --> 00:59:09,150 And so now we can actually test this. 897 00:59:09,150 --> 00:59:24,070 We can say const token is await login username and passwords. 898 00:59:24,070 --> 00:59:31,110 So rather than writing that out, let's just do expect that if we invoke 899 00:59:31,110 --> 00:59:33,960 the actions.logInUser-- 900 00:59:33,960 --> 00:59:40,051 901 00:59:40,051 --> 00:59:42,176 let's actually just do exactly what we did up here. 902 00:59:42,176 --> 00:59:45,420 903 00:59:45,420 --> 00:59:48,460 So let's await actions.logInUser. 904 00:59:48,460 --> 00:59:51,370 Let's invoke with the username and password credentials 905 00:59:51,370 --> 00:59:55,390 that we know are correct, u and p. 906 00:59:55,390 --> 00:59:58,930 So let's do u here and p here. 907 00:59:58,930 --> 01:00:01,930 And then what do we also have to pass into this function? 908 01:00:01,930 --> 01:00:05,180 Well, we need to pass in the login function that it should be using. 909 01:00:05,180 --> 01:00:06,730 And so we just wrote it here. 910 01:00:06,730 --> 01:00:08,990 So let's also pass in the login. 911 01:00:08,990 --> 01:00:14,860 And let's just call it mock login so we know it's a mock. 912 01:00:14,860 --> 01:00:22,170 913 01:00:22,170 --> 01:00:25,032 And then we also passing our mock dispatch. 914 01:00:25,032 --> 01:00:25,990 And then what do we do? 915 01:00:25,990 --> 01:00:28,950 Well, now what? 916 01:00:28,950 --> 01:00:33,690 We expect that the mock dispatch has now dispatched more than one things. 917 01:00:33,690 --> 01:00:41,020 One should be-- so mockDispatch.mock.calls. 918 01:00:41,020 --> 01:00:44,140 So if we do the first one, what's not going to be? 919 01:00:44,140 --> 01:00:51,850 What is the first thing that our logInUser action dispatches? 920 01:00:51,850 --> 01:00:57,520 Well, if we refer to our actions.js file, 921 01:00:57,520 --> 01:01:03,880 we see that always the first thing that gets dispatched is that login set. 922 01:01:03,880 --> 01:01:06,190 But now for this particular test, since we're 923 01:01:06,190 --> 01:01:13,210 testing that the login fulfilled action gets dispatched, 924 01:01:13,210 --> 01:01:17,800 now we're interested in what's dispatched second. 925 01:01:17,800 --> 01:01:22,000 And so let's go ahead and actually match against the second one. 926 01:01:22,000 --> 01:01:24,850 927 01:01:24,850 --> 01:01:29,050 And we can do .toEqual that action. 928 01:01:29,050 --> 01:01:33,465 Or, what's better is we can just do to match the snapshot. 929 01:01:33,465 --> 01:01:38,460 930 01:01:38,460 --> 01:01:41,354 Well, maybe we should do both because for the first time, 931 01:01:41,354 --> 01:01:43,270 we're not really guaranteed that it's actually 932 01:01:43,270 --> 01:01:45,550 going to be what we want it to be. 933 01:01:45,550 --> 01:01:48,260 934 01:01:48,260 --> 01:01:52,720 So let's also expect that the first one is 935 01:01:52,720 --> 01:02:05,325 going to equal the type of login filled with a payload that contains 936 01:02:05,325 --> 01:02:14,130 a token, which is thisIsATestToken. 937 01:02:14,130 --> 01:02:27,120 938 01:02:27,120 --> 01:02:33,680 And now, assuming there are no syntax errors, 939 01:02:33,680 --> 01:02:36,189 that should be what we expect it to be. 940 01:02:36,189 --> 01:02:37,980 So let's go ahead and just run these tests. 941 01:02:37,980 --> 01:02:44,310 942 01:02:44,310 --> 01:02:47,087 And await is a reserved word. 943 01:02:47,087 --> 01:02:47,920 What does that mean? 944 01:02:47,920 --> 01:02:51,445 It means we forgot to use async. 945 01:02:51,445 --> 01:02:55,230 946 01:02:55,230 --> 01:03:01,830 So let's go ahead and make the second test also a async. 947 01:03:01,830 --> 01:03:10,520 948 01:03:10,520 --> 01:03:15,990 And now we can see whether or not our test passes. 949 01:03:15,990 --> 01:03:25,170 It does not because it can't read property two of undefined. 950 01:03:25,170 --> 01:03:26,960 Oh, we don't want two here. 951 01:03:26,960 --> 01:03:27,710 We want one. 952 01:03:27,710 --> 01:03:30,320 I was not zero indexing properly. 953 01:03:30,320 --> 01:03:33,580 954 01:03:33,580 --> 01:03:41,350 Because if we want to get the second value in an array, which array index do 955 01:03:41,350 --> 01:03:43,000 we actually want to look into? 956 01:03:43,000 --> 01:03:44,220 Probably one, right? 957 01:03:44,220 --> 01:03:49,040 958 01:03:49,040 --> 01:03:49,540 Great. 959 01:03:49,540 --> 01:03:52,090 So now-- oh, there's also a bug. 960 01:03:52,090 --> 01:03:55,700 961 01:03:55,700 --> 01:03:57,850 We don't want the second. 962 01:03:57,850 --> 01:04:01,730 We don't want the third array index of this. 963 01:04:01,730 --> 01:04:03,890 We actually want array index zero. 964 01:04:03,890 --> 01:04:06,410 965 01:04:06,410 --> 01:04:14,380 And so now, hopefully this passes. 966 01:04:14,380 --> 01:04:15,880 And we see an error. 967 01:04:15,880 --> 01:04:19,960 It might just be the wrong shape. 968 01:04:19,960 --> 01:04:23,350 Yeah, the payload is just the string rather 969 01:04:23,350 --> 01:04:27,100 than being an object with a token in the string, which might actually 970 01:04:27,100 --> 01:04:35,740 be a bug if we want to follow a very strict shape in our flux action. 971 01:04:35,740 --> 01:04:41,540 But let's actually just write the tests to fit the function for now, 972 01:04:41,540 --> 01:04:43,870 since we're already using that function successfully. 973 01:04:43,870 --> 01:04:47,230 But our test actually just kind of caught a bug for us, which is cool. 974 01:04:47,230 --> 01:04:50,540 975 01:04:50,540 --> 01:04:56,560 So let's go ahead and just update our test so that it passes. 976 01:04:56,560 --> 01:05:00,160 977 01:05:00,160 --> 01:05:05,290 So rather than having the payload be an object with a key called token, 978 01:05:05,290 --> 01:05:08,530 we just pass in the token as the payload. 979 01:05:08,530 --> 01:05:16,050 And now we'll see that the test passes correctly. 980 01:05:16,050 --> 01:05:16,550 Awesome. 981 01:05:16,550 --> 01:05:19,790 So let's quickly handle our last case. 982 01:05:19,790 --> 01:05:24,320 983 01:05:24,320 --> 01:05:29,390 We want to ensure that we dispatch login rejected if we try to log in 984 01:05:29,390 --> 01:05:31,940 with the incorrect credentials. 985 01:05:31,940 --> 01:05:41,240 So we can move that mock login function outside so we can use it again. 986 01:05:41,240 --> 01:05:46,680 987 01:05:46,680 --> 01:05:49,860 We can also delete this if we wanted to since we 988 01:05:49,860 --> 01:05:52,110 know that the snapshot is correct. 989 01:05:52,110 --> 01:05:53,760 But it's not that expensive to run. 990 01:05:53,760 --> 01:05:56,910 Let's just keep it in there for extra safety. 991 01:05:56,910 --> 01:06:07,184 And let's just do it dispatches login rejected. 992 01:06:07,184 --> 01:06:09,100 And let's just copy and paste the whole thing. 993 01:06:09,100 --> 01:06:13,320 994 01:06:13,320 --> 01:06:17,632 So we want it to dispatch login rejected with incorrect credentials. 995 01:06:17,632 --> 01:06:23,300 996 01:06:23,300 --> 01:06:28,200 And so now let's just pass in an empty string, an empty string. 997 01:06:28,200 --> 01:06:33,100 We expect now the call not to be type actions login fulfilled, 998 01:06:33,100 --> 01:06:43,365 but to be type login rejected. 999 01:06:43,365 --> 01:06:49,240 1000 01:06:49,240 --> 01:06:51,430 And we want it to match the snapshot. 1001 01:06:51,430 --> 01:06:53,040 So let's just run the test. 1002 01:06:53,040 --> 01:06:57,230 1003 01:06:57,230 --> 01:06:59,418 Maybe we're passing in the error string, as well. 1004 01:06:59,418 --> 01:07:03,132 1005 01:07:03,132 --> 01:07:05,090 So the payload is incorrect creds because we're 1006 01:07:05,090 --> 01:07:06,810 passing in the error string. 1007 01:07:06,810 --> 01:07:08,480 So let's just update that really quick. 1008 01:07:08,480 --> 01:07:13,070 1009 01:07:13,070 --> 01:07:16,010 Because right now, we're only checking to ensure 1010 01:07:16,010 --> 01:07:22,760 that the first dispatch, or the array index one, or the second dispatch 1011 01:07:22,760 --> 01:07:24,970 has a type actions login rejected. 1012 01:07:24,970 --> 01:07:29,730 But it turns out we're also passing in the error message here as the payload. 1013 01:07:29,730 --> 01:07:35,850 So let's make sure that this is whatever we called up here. 1014 01:07:35,850 --> 01:07:38,207 1015 01:07:38,207 --> 01:07:39,790 And we can actually abstract that out. 1016 01:07:39,790 --> 01:07:50,060 1017 01:07:50,060 --> 01:07:55,790 So let's ensure that the payload is the error message. 1018 01:07:55,790 --> 01:08:03,470 And while we're at it, we can also not hard code the token here, but also 1019 01:08:03,470 --> 01:08:04,220 abstract that out. 1020 01:08:04,220 --> 01:08:12,880 1021 01:08:12,880 --> 01:08:19,510 So now we're guaranteed that whatever fake token 1022 01:08:19,510 --> 01:08:22,529 we return from the mock login on successful 1023 01:08:22,529 --> 01:08:26,340 is the exact string that we're checking against in the payload, 1024 01:08:26,340 --> 01:08:28,236 eventually, in our test. 1025 01:08:28,236 --> 01:08:30,569 So that's just abstracting it out so that we're not hard 1026 01:08:30,569 --> 01:08:32,590 coding things everywhere. 1027 01:08:32,590 --> 01:08:36,240 And so now let's run our tests. 1028 01:08:36,240 --> 01:08:39,580 And hopefully, every single one will pass. 1029 01:08:39,580 --> 01:08:40,080 Great. 1030 01:08:40,080 --> 01:08:41,520 So let's take a short break. 1031 01:08:41,520 --> 01:08:46,770 And when we come back, we'll see how to test some more complicated structures. 1032 01:08:46,770 --> 01:08:47,979 Hello, and welcome back. 1033 01:08:47,979 --> 01:08:50,250 So before the break, we were talking about testing 1034 01:08:50,250 --> 01:08:54,090 and how to test things like simple Redux actions, 1035 01:08:54,090 --> 01:08:57,081 and also things like asynchronous Redux actions. 1036 01:08:57,081 --> 01:08:58,830 And a great question came up during break. 1037 01:08:58,830 --> 01:09:05,850 And it was, hey, how come our tests look very similar to the functions 1038 01:09:05,850 --> 01:09:07,050 that we've implemented? 1039 01:09:07,050 --> 01:09:09,569 And is it really testing what it should be testing? 1040 01:09:09,569 --> 01:09:14,460 Because it's basically just implementing the function that we're testing. 1041 01:09:14,460 --> 01:09:20,890 And let me show you an explanation. 1042 01:09:20,890 --> 01:09:24,200 So in our particular logInUser function here, 1043 01:09:24,200 --> 01:09:27,870 there are really only two possible paths for our code to take. 1044 01:09:27,870 --> 01:09:34,050 Either the login succeeds and we fulfill that login, or the login 1045 01:09:34,050 --> 01:09:36,029 fails and the login is rejected. 1046 01:09:36,029 --> 01:09:40,710 And so you can think of it as a tree of the possible different ways 1047 01:09:40,710 --> 01:09:47,620 this code can happen, or just a tree of all of the possibilities. 1048 01:09:47,620 --> 01:09:49,529 And so there were really just two code paths. 1049 01:09:49,529 --> 01:09:54,480 Either first, you dispatch login sent, and then you dispatch login fulfilled. 1050 01:09:54,480 --> 01:09:58,830 Or you dispatch login sent, and then you dispatch login rejected. 1051 01:09:58,830 --> 01:10:00,720 So there are really only two branches. 1052 01:10:00,720 --> 01:10:03,570 And so in our tests, we're actually testing three different things. 1053 01:10:03,570 --> 01:10:07,680 We're testing first that we do what the first line here, 1054 01:10:07,680 --> 01:10:10,557 where we test whether login is sent. 1055 01:10:10,557 --> 01:10:12,140 And then we test both of the branches. 1056 01:10:12,140 --> 01:10:16,110 So either this branch is taken, and we fulfill the login, 1057 01:10:16,110 --> 01:10:18,840 or this branch is taken, and we reject the login. 1058 01:10:18,840 --> 01:10:22,200 And in this particular test here, we're testing 1059 01:10:22,200 --> 01:10:27,060 that bottom branch, whether or not we-- 1060 01:10:27,060 --> 01:10:27,760 oops. 1061 01:10:27,760 --> 01:10:29,340 I need to scroll down a little bit. 1062 01:10:29,340 --> 01:10:36,270 1063 01:10:36,270 --> 01:10:39,040 So first we either test that the login is sent. 1064 01:10:39,040 --> 01:10:41,600 So we test the first line of code. 1065 01:10:41,600 --> 01:10:43,350 And then we test both possible branches. 1066 01:10:43,350 --> 01:10:51,870 We test either that login fulfilled is reached or login rejected is reached. 1067 01:10:51,870 --> 01:10:55,400 And so if we want to dig in a little bit into that login rejected, 1068 01:10:55,400 --> 01:10:59,990 we can see that although it's similar to the code that is written in login user, 1069 01:10:59,990 --> 01:11:02,530 it's not really reimplementing anything. 1070 01:11:02,530 --> 01:11:06,110 In login user what we're doing is we're first dispatching an action. 1071 01:11:06,110 --> 01:11:09,420 And then we're checking the result of our login function. 1072 01:11:09,420 --> 01:11:12,560 And so we're going to attempt to log in with the username and password. 1073 01:11:12,560 --> 01:11:14,630 And depending on how that goes, we're either 1074 01:11:14,630 --> 01:11:17,930 going to take the branch where we fulfill the login, 1075 01:11:17,930 --> 01:11:21,020 or we take the branch where we reject the login. 1076 01:11:21,020 --> 01:11:24,350 And so if you look at our logic in our test here, 1077 01:11:24,350 --> 01:11:27,110 first we create a mock dispatch. 1078 01:11:27,110 --> 01:11:29,570 We have already created a mock login. 1079 01:11:29,570 --> 01:11:33,080 But the first thing that we do is we execute some logic 1080 01:11:33,080 --> 01:11:34,430 where the code branches. 1081 01:11:34,430 --> 01:11:40,231 And so we try to log in the user using an empty string for both the 1082 01:11:40,231 --> 01:11:41,480 the username and the password. 1083 01:11:41,480 --> 01:11:47,870 So we're sending bogus information, hoping that the login gets rejected. 1084 01:11:47,870 --> 01:11:49,700 And so that's what we're testing down here. 1085 01:11:49,700 --> 01:11:59,900 Were saying, hey, ensure that the action that gets dispatched is of type login 1086 01:11:59,900 --> 01:12:02,780 rejected and has a payload of the error message. 1087 01:12:02,780 --> 01:12:08,820 And just as a sanity check, we're also going to do a match snapshot here. 1088 01:12:08,820 --> 01:12:12,590 And we can actually remove the first one once we know that the snapshot has 1089 01:12:12,590 --> 01:12:14,930 the correct action. 1090 01:12:14,930 --> 01:12:19,010 And so just to reiterate, even though the test 1091 01:12:19,010 --> 01:12:24,560 looks very similar in the way it's laid out to the function, 1092 01:12:24,560 --> 01:12:28,610 it actually does test it pretty well because we 1093 01:12:28,610 --> 01:12:31,710 have one test to do the first line. 1094 01:12:31,710 --> 01:12:36,290 Then we have two separate tests to test either branch of the possibility 1095 01:12:36,290 --> 01:12:41,420 where really the only logic lies, whether we login successfully 1096 01:12:41,420 --> 01:12:44,220 or unsuccessfully. 1097 01:12:44,220 --> 01:12:47,540 So, yeah, hopefully that addresses the question that came up. 1098 01:12:47,540 --> 01:12:52,070 And now let's forge ahead. 1099 01:12:52,070 --> 01:12:54,120 One more thing to note-- 1100 01:12:54,120 --> 01:12:58,460 I was curious earlier why our tests weren't 1101 01:12:58,460 --> 01:13:01,070 being enumerated when we run npm test. 1102 01:13:01,070 --> 01:13:05,450 And it's because if you run npm test-- 1103 01:13:05,450 --> 01:13:11,240 or if you run Jest with a flag called verbose, 1104 01:13:11,240 --> 01:13:13,745 that's what triggers all of the tests to be enumerated. 1105 01:13:13,745 --> 01:13:18,980 And so if we run with that --verbose flag, we then see all of the groupings 1106 01:13:18,980 --> 01:13:22,220 that we dictated in our test files. 1107 01:13:22,220 --> 01:13:27,950 And so we see in actions.test.js, we see the first describe block, 1108 01:13:27,950 --> 01:13:31,130 which describes the update user returning actions. 1109 01:13:31,130 --> 01:13:37,400 And then for each it block, we see those strings being repeated here. 1110 01:13:37,400 --> 01:13:39,960 And so the first it was it returns an action. 1111 01:13:39,960 --> 01:13:41,564 And then it handles an empty object. 1112 01:13:41,564 --> 01:13:42,980 And then it handles an empty name. 1113 01:13:42,980 --> 01:13:47,930 And we see that they all executed correct with that green check mark 1114 01:13:47,930 --> 01:13:48,590 there. 1115 01:13:48,590 --> 01:13:50,090 We see the second group here. 1116 01:13:50,090 --> 01:13:55,590 And we also see all of the tests that we specified in sum.test.js. 1117 01:13:55,590 --> 01:13:59,810 And so these were not grouped using a describe block like these ones. 1118 01:13:59,810 --> 01:14:03,350 They were just using that test function. 1119 01:14:03,350 --> 01:14:06,390 And so they show just as separate tests here. 1120 01:14:06,390 --> 01:14:11,540 And so if we wanted to show that entire enumeration of all the tests every time 1121 01:14:11,540 --> 01:14:17,360 we run npm test, then we need to change our package.json 1122 01:14:17,360 --> 01:14:19,310 to ensure that that flag is passed. 1123 01:14:19,310 --> 01:14:21,290 And so tests. 1124 01:14:21,290 --> 01:14:26,090 We should --verbose here and also here. 1125 01:14:26,090 --> 01:14:29,520 1126 01:14:29,520 --> 01:14:36,050 So now when you run npm test, we'll see that all of the tests 1127 01:14:36,050 --> 01:14:38,600 are enumerated for us. 1128 01:14:38,600 --> 01:14:39,100 Cool. 1129 01:14:39,100 --> 01:14:41,240 So we talked about a lot of different unit tests 1130 01:14:41,240 --> 01:14:44,820 and how we would test our actions. 1131 01:14:44,820 --> 01:14:47,660 And so now let's test something a little bit more involved. 1132 01:14:47,660 --> 01:14:53,060 So let's test our Redux reducers. 1133 01:14:53,060 --> 01:14:57,185 So just check our reducers the way that we implemented it before. 1134 01:14:57,185 --> 01:15:00,020 1135 01:15:00,020 --> 01:15:07,190 Let's just remove this to shut up ESLint. 1136 01:15:07,190 --> 01:15:09,220 So now there are no linting errors, we can 1137 01:15:09,220 --> 01:15:12,850 see that we have two different reducers here. 1138 01:15:12,850 --> 01:15:13,570 1139 01:15:13,570 --> 01:15:16,530 So one handles all of our contacts. 1140 01:15:16,530 --> 01:15:20,840 And so our contacts reducer takes the previous state and an action, 1141 01:15:20,840 --> 01:15:24,770 and depending on what the action does, it returns a new state. 1142 01:15:24,770 --> 01:15:27,760 So if the action's type is update contact, 1143 01:15:27,760 --> 01:15:31,720 we add a new contact into the state and return it. 1144 01:15:31,720 --> 01:15:35,650 And the way that we do that is we use this array spread. 1145 01:15:35,650 --> 01:15:39,880 So we basically clone the array from the state, 1146 01:15:39,880 --> 01:15:43,930 and then tack on at the and the action.payload. 1147 01:15:43,930 --> 01:15:46,000 If the action is not update contact, we just 1148 01:15:46,000 --> 01:15:50,606 return to state unchanged because we don't really have anything to change. 1149 01:15:50,606 --> 01:15:52,480 Our user reducer is a little more complicated 1150 01:15:52,480 --> 01:15:56,110 because there are different types that we want to check against. 1151 01:15:56,110 --> 01:15:58,865 If it's update user, then we merge the payload in. 1152 01:15:58,865 --> 01:16:04,000 If it's update contact, we merge this new object 1153 01:16:04,000 --> 01:16:06,940 where the previous contact is the payload. 1154 01:16:06,940 --> 01:16:10,790 And similar thing for login fulfilled or login rejected. 1155 01:16:10,790 --> 01:16:14,500 And if none of these match, then we just return the state unchanged. 1156 01:16:14,500 --> 01:16:18,520 And how are these exposed to Redux? 1157 01:16:18,520 --> 01:16:22,690 Well, we have our single reducer, which combines these two. 1158 01:16:22,690 --> 01:16:30,360 And so the user reducer is responsible for any changes in the user key. 1159 01:16:30,360 --> 01:16:35,430 And for any changes in the contacts key, it gets passed to that contact reducer. 1160 01:16:35,430 --> 01:16:38,140 So let's go ahead and create a few tests to make sure 1161 01:16:38,140 --> 01:16:41,810 that the reducer is doing what we want it to do. 1162 01:16:41,810 --> 01:16:46,140 So we do this in a reducer.test.js file. 1163 01:16:46,140 --> 01:16:51,580 The first thing that we want to do is let's disable ESLint 1164 01:16:51,580 --> 01:16:52,810 so it's easier to read. 1165 01:16:52,810 --> 01:16:58,452 1166 01:16:58,452 --> 01:16:59,660 And let's import the reducer. 1167 01:16:59,660 --> 01:17:07,070 1168 01:17:07,070 --> 01:17:09,415 And let's also import our actions. 1169 01:17:09,415 --> 01:17:17,090 1170 01:17:17,090 --> 01:17:17,590 Cool. 1171 01:17:17,590 --> 01:17:22,870 So let's just pick a couple things at random to test for. 1172 01:17:22,870 --> 01:17:27,970 In reality, we'd want to test all of our functionality in reducer. 1173 01:17:27,970 --> 01:17:30,670 But since we don't have time for all that, 1174 01:17:30,670 --> 01:17:32,840 let's just check a couple of things. 1175 01:17:32,840 --> 01:17:34,470 Let's just check contact reducer. 1176 01:17:34,470 --> 01:17:39,220 If we add a new contact, let's ensure that it makes it into our state. 1177 01:17:39,220 --> 01:17:48,555 So let's do describe the contact reducer. 1178 01:17:48,555 --> 01:17:55,840 1179 01:17:55,840 --> 01:18:06,480 And it successfully adds new user. 1180 01:18:06,480 --> 01:18:09,440 And how are we going to check it for that? 1181 01:18:09,440 --> 01:18:16,810 Well, first we should expect the result of passing 1182 01:18:16,810 --> 01:18:19,450 in user reducer or the reducer-- 1183 01:18:19,450 --> 01:18:23,510 1184 01:18:23,510 --> 01:18:26,230 so the reducer takes a state and an action. 1185 01:18:26,230 --> 01:18:30,020 So let's just create a default state for now. 1186 01:18:30,020 --> 01:18:40,370 So let's have a default state just be-- 1187 01:18:40,370 --> 01:18:45,612 let's have the user be an empty object and contacts be an empty array. 1188 01:18:45,612 --> 01:18:48,770 1189 01:18:48,770 --> 01:18:51,910 And I say we should pass the reducer in an initial state. 1190 01:18:51,910 --> 01:18:54,717 So let's pass the default state here. 1191 01:18:54,717 --> 01:18:56,300 And it should take an action, as well. 1192 01:18:56,300 --> 01:19:00,480 And so let's just pull in an action creator from our actions file. 1193 01:19:00,480 --> 01:19:04,050 And I believe it's called add user. 1194 01:19:04,050 --> 01:19:19,200 And let's add a user with a name of test user and a phone of that 1195 01:19:19,200 --> 01:19:23,100 and expect it to just match the snapshot-- 1196 01:19:23,100 --> 01:19:24,930 to match snapshot. 1197 01:19:24,930 --> 01:19:29,750 1198 01:19:29,750 --> 01:19:31,500 This might actually be called add contact. 1199 01:19:31,500 --> 01:19:45,300 1200 01:19:45,300 --> 01:19:48,540 And just to make it a little bit more readable, do that. 1201 01:19:48,540 --> 01:19:51,960 1202 01:19:51,960 --> 01:19:55,720 And now let's also run our tests in watch mode 1203 01:19:55,720 --> 01:19:57,760 so we can see what happens as we write them. 1204 01:19:57,760 --> 01:20:03,260 1205 01:20:03,260 --> 01:20:08,020 And so we see that the test is written. 1206 01:20:08,020 --> 01:20:10,250 One snapshot written in one test suite. 1207 01:20:10,250 --> 01:20:19,950 So now let's change this to make sure the snapshot is what we want it to be. 1208 01:20:19,950 --> 01:20:24,380 So let's test user, exclamation point. 1209 01:20:24,380 --> 01:20:25,340 Save that. 1210 01:20:25,340 --> 01:20:27,950 The snapshot test should fail. 1211 01:20:27,950 --> 01:20:32,060 Let's go see why it failed. 1212 01:20:32,060 --> 01:20:38,990 Because our object that was our state now contains the contacts 1213 01:20:38,990 --> 01:20:46,040 where the array is test user with an exclamation point rather than without. 1214 01:20:46,040 --> 01:20:49,140 But it looks fine the way it was before. 1215 01:20:49,140 --> 01:20:52,760 So let's just revert. 1216 01:20:52,760 --> 01:20:56,740 And so now we know that this snapshot is what we want it to be. 1217 01:20:56,740 --> 01:21:01,860 Let's also describe the user reducer. 1218 01:21:01,860 --> 01:21:05,550 1219 01:21:05,550 --> 01:21:12,210 And that successfully updates user. 1220 01:21:12,210 --> 01:21:15,510 So let's expect the user, if we pass in the default state, 1221 01:21:15,510 --> 01:21:19,710 let's try to update the user. 1222 01:21:19,710 --> 01:21:21,170 Maybe that's called update user. 1223 01:21:21,170 --> 01:21:27,120 1224 01:21:27,120 --> 01:21:30,210 And just change the name to test user. 1225 01:21:30,210 --> 01:21:34,230 Let's see what the tests have to say. 1226 01:21:34,230 --> 01:21:35,970 One snapshot written. 1227 01:21:35,970 --> 01:21:38,040 We can see exactly what the snapshot is. 1228 01:21:38,040 --> 01:21:40,080 We can open up the snapshot file. 1229 01:21:40,080 --> 01:21:46,860 Or we can just change this really quick so that the diff shows. 1230 01:21:46,860 --> 01:21:52,700 We can see that now the snapshot test fails, as expected, 1231 01:21:52,700 --> 01:22:01,490 because now the user, the name is test user with an exclamation point. 1232 01:22:01,490 --> 01:22:02,975 It was fine the way it was before. 1233 01:22:02,975 --> 01:22:03,850 So let's just revert. 1234 01:22:03,850 --> 01:22:07,820 1235 01:22:07,820 --> 01:22:11,450 And now our test should pass because the snapshot matches the snapshot 1236 01:22:11,450 --> 01:22:14,540 that it was before. 1237 01:22:14,540 --> 01:22:16,700 And it does indeed pass. 1238 01:22:16,700 --> 01:22:17,960 Great. 1239 01:22:17,960 --> 01:22:24,680 So now we've gone and tested our reducer. 1240 01:22:24,680 --> 01:22:26,420 Obviously, there's a lot more to test. 1241 01:22:26,420 --> 01:22:30,920 But since we're running low on time, we'll just leave that untested for now. 1242 01:22:30,920 --> 01:22:33,540 1243 01:22:33,540 --> 01:22:36,590 So now we've basically tested everything in Redux. 1244 01:22:36,590 --> 01:22:41,390 But we're yet to actually touch any React or React Native. 1245 01:22:41,390 --> 01:22:45,080 And so now let's look at some integration tests. 1246 01:22:45,080 --> 01:22:49,790 And so how might we want to go about testing React components? 1247 01:22:49,790 --> 01:22:52,280 Well, we can use Jest snapshotting. 1248 01:22:52,280 --> 01:22:56,420 Just like we were snapshotting and looking at any diffs 1249 01:22:56,420 --> 01:23:01,070 between what changed in the output of the reducers or any of the actions, 1250 01:23:01,070 --> 01:23:07,460 we can also use the snapshot feature to test the output of React component 1251 01:23:07,460 --> 01:23:09,640 rendering. 1252 01:23:09,640 --> 01:23:14,300 And so how are we going to render React outside 1253 01:23:14,300 --> 01:23:17,000 of the context of our application? 1254 01:23:17,000 --> 01:23:19,250 Well, it turns out React allows us to do that 1255 01:23:19,250 --> 01:23:24,740 by using this React test renderer, which is maintained by the React team. 1256 01:23:24,740 --> 01:23:29,882 It allows us to just render components outside the context of an application. 1257 01:23:29,882 --> 01:23:32,090 And so the docs are here if you want to look at them. 1258 01:23:32,090 --> 01:23:37,580 But we'll be using that in the demo. 1259 01:23:37,580 --> 01:23:41,210 One additional thing is that now we're going 1260 01:23:41,210 --> 01:23:46,310 to need to configure Jest a little bit more so that it worked with React. 1261 01:23:46,310 --> 01:23:49,310 It turns out the Expo team has done this for us. 1262 01:23:49,310 --> 01:23:52,040 Jest Expo has all the configuration we need. 1263 01:23:52,040 --> 01:23:56,190 And we can just look at the docs here to see how to use that. 1264 01:23:56,190 --> 01:23:59,960 So let's just take a quick peek. 1265 01:23:59,960 --> 01:24:05,121 We can see that we need to run npm install jest expo and save dev. 1266 01:24:05,121 --> 01:24:06,370 So let's go ahead and do that. 1267 01:24:06,370 --> 01:24:10,840 1268 01:24:10,840 --> 01:24:15,890 And while it installs, we can also see that we 1269 01:24:15,890 --> 01:24:19,250 need to add a little bit to our package.json. 1270 01:24:19,250 --> 01:24:21,280 We already have a test script. 1271 01:24:21,280 --> 01:24:26,720 But we need to add a Jest key that let's Jest know to use the configuration 1272 01:24:26,720 --> 01:24:30,290 preset specified within Jest Expo. 1273 01:24:30,290 --> 01:24:33,400 So let's just cut and paste this into our package.json. 1274 01:24:33,400 --> 01:24:41,010 1275 01:24:41,010 --> 01:24:50,098 So we can now open up package.json and just add our Jest preset. 1276 01:24:50,098 --> 01:24:59,440 1277 01:24:59,440 --> 01:25:03,410 So now in theory, we are all ready to try our integration tests. 1278 01:25:03,410 --> 01:25:09,340 And so now let's actually try this thing called test-driven development. 1279 01:25:09,340 --> 01:25:12,730 And so there's another question that came up during break that was, 1280 01:25:12,730 --> 01:25:15,211 hey, it looks like we wrote our entire app. 1281 01:25:15,211 --> 01:25:16,960 And now we're writing test after the fact. 1282 01:25:16,960 --> 01:25:18,880 Is that what we should be doing? 1283 01:25:18,880 --> 01:25:24,190 It turns out there's actually a strategy to writing tests and writing code. 1284 01:25:24,190 --> 01:25:27,727 And it's called test-driven development, whereby the tests drive 1285 01:25:27,727 --> 01:25:29,060 what you should be implementing. 1286 01:25:29,060 --> 01:25:32,530 And as long as you know exactly what you want to be implementing, 1287 01:25:32,530 --> 01:25:35,950 you can write the tests first, and then implement 1288 01:25:35,950 --> 01:25:38,560 the components or whatever you're implementing such 1289 01:25:38,560 --> 01:25:40,060 that it fulfills all of the tests. 1290 01:25:40,060 --> 01:25:45,100 And so the tests are less tests and more the specification. 1291 01:25:45,100 --> 01:25:47,260 Or in other words, what should this function, 1292 01:25:47,260 --> 01:25:50,060 or what should this component, be doing? 1293 01:25:50,060 --> 01:25:56,140 And so let's actually write a simple button component and use 1294 01:25:56,140 --> 01:25:59,640 test-driven development to do so. 1295 01:25:59,640 --> 01:26:01,750 So let's just make a components directory. 1296 01:26:01,750 --> 01:26:04,750 1297 01:26:04,750 --> 01:26:07,390 And let's actually write the test file first. 1298 01:26:07,390 --> 01:26:09,716 So let's do MyButton.test.js. 1299 01:26:09,716 --> 01:26:13,210 1300 01:26:13,210 --> 01:26:21,110 And shut up ESLint for now. 1301 01:26:21,110 --> 01:26:28,794 And first we're going to want to import MyButton from a file 1302 01:26:28,794 --> 01:26:29,960 that we haven't yet written. 1303 01:26:29,960 --> 01:26:31,793 But it'll be eventually written in MyButton. 1304 01:26:31,793 --> 01:26:34,015 1305 01:26:34,015 --> 01:26:35,140 And what do you want to do? 1306 01:26:35,140 --> 01:26:36,556 Well, first we should describe it. 1307 01:26:36,556 --> 01:26:50,400 1308 01:26:50,400 --> 01:26:54,830 So let's see what happens in MyButton. 1309 01:26:54,830 --> 01:26:56,120 Well, first, it should render. 1310 01:26:56,120 --> 01:26:58,190 It should just appear. 1311 01:26:58,190 --> 01:27:00,020 So let's just test that it renders. 1312 01:27:00,020 --> 01:27:04,730 1313 01:27:04,730 --> 01:27:07,060 And so now we've run into a little bit of difficulty. 1314 01:27:07,060 --> 01:27:10,320 How do we ensure that it's rendering? 1315 01:27:10,320 --> 01:27:13,960 So this is actually what React test renderer does. 1316 01:27:13,960 --> 01:27:16,790 It allows us to render these components outside the app 1317 01:27:16,790 --> 01:27:18,960 to make sure they actually exist. 1318 01:27:18,960 --> 01:27:20,550 So let's go ahead and do that. 1319 01:27:20,550 --> 01:27:30,170 So let's do import render from react-test-render. 1320 01:27:30,170 --> 01:27:33,430 1321 01:27:33,430 --> 01:27:39,870 And we can do const button is render.create. 1322 01:27:39,870 --> 01:27:41,120 And what do we want to create? 1323 01:27:41,120 --> 01:27:43,370 Well, we just want to do a MyButton. 1324 01:27:43,370 --> 01:27:46,820 1325 01:27:46,820 --> 01:27:51,164 And maybe we should turn into JSON so it's easy to match against. 1326 01:27:51,164 --> 01:27:51,830 Just do .toJSON. 1327 01:27:51,830 --> 01:27:54,470 1328 01:27:54,470 --> 01:27:57,860 And then let's just make sure that it matches 1329 01:27:57,860 --> 01:27:59,420 the snapshot that it was before. 1330 01:27:59,420 --> 01:28:06,975 So let's do expect button to match the snapshot. 1331 01:28:06,975 --> 01:28:16,260 1332 01:28:16,260 --> 01:28:18,580 And now let's run our tests in watch mode 1333 01:28:18,580 --> 01:28:21,560 so we can actually implement the button as we go. 1334 01:28:21,560 --> 01:28:25,700 1335 01:28:25,700 --> 01:28:28,190 So it looks like it's erroring. 1336 01:28:28,190 --> 01:28:29,324 The test failed. 1337 01:28:29,324 --> 01:28:29,990 Why did it fail? 1338 01:28:29,990 --> 01:28:33,380 Well, obviously, it can't find my button because we haven't even 1339 01:28:33,380 --> 01:28:35,190 written the file yet. 1340 01:28:35,190 --> 01:28:38,190 So let's go ahead and do that. 1341 01:28:38,190 --> 01:28:42,560 So let's open up MyButton.js. 1342 01:28:42,560 --> 01:28:48,770 And let's just do export default empty. 1343 01:28:48,770 --> 01:28:50,360 Just an empty function. 1344 01:28:50,360 --> 01:28:51,390 We'll save that. 1345 01:28:51,390 --> 01:28:53,270 We'll see what the tests have to say. 1346 01:28:53,270 --> 01:28:54,410 OK. 1347 01:28:54,410 --> 01:28:57,830 Now a different error. 1348 01:28:57,830 --> 01:28:59,480 Renders, it failed. 1349 01:28:59,480 --> 01:29:00,710 React isn't defined. 1350 01:29:00,710 --> 01:29:02,870 Maybe we should import React from React. 1351 01:29:02,870 --> 01:29:09,910 1352 01:29:09,910 --> 01:29:15,805 So in both these files, let's do import React from React. 1353 01:29:15,805 --> 01:29:25,640 1354 01:29:25,640 --> 01:29:27,030 And now the tests run again. 1355 01:29:27,030 --> 01:29:28,493 And another one fails. 1356 01:29:28,493 --> 01:29:29,459 What happened here? 1357 01:29:29,459 --> 01:29:32,360 1358 01:29:32,360 --> 01:29:35,490 Well, it didn't actually render. 1359 01:29:35,490 --> 01:29:37,190 Invariant violation. 1360 01:29:37,190 --> 01:29:40,610 We wanted a component, but nothing was returned from render. 1361 01:29:40,610 --> 01:29:41,390 Well, great. 1362 01:29:41,390 --> 01:29:42,780 Our tests caught an error. 1363 01:29:42,780 --> 01:29:45,057 So it's not actually rendering anything. 1364 01:29:45,057 --> 01:29:46,640 So now let's actually render a button. 1365 01:29:46,640 --> 01:29:58,030 1366 01:29:58,030 --> 01:30:03,165 So let's import button from react-native. 1367 01:30:03,165 --> 01:30:06,560 1368 01:30:06,560 --> 01:30:08,865 And now we can do just return a button. 1369 01:30:08,865 --> 01:30:13,486 1370 01:30:13,486 --> 01:30:23,610 And now we're seeing a test failure. 1371 01:30:23,610 --> 01:30:26,030 We can go up. 1372 01:30:26,030 --> 01:30:30,270 And we can see, oh, this failed because we're not using button correctly. 1373 01:30:30,270 --> 01:30:31,950 We need to pass a title to button. 1374 01:30:31,950 --> 01:30:33,660 OK, so our test's still failing. 1375 01:30:33,660 --> 01:30:35,950 Let's go back and fix that. 1376 01:30:35,950 --> 01:30:42,150 So we can say the title should be, I don't know, test button. 1377 01:30:42,150 --> 01:30:51,000 And maybe let's also get ahead and pass on press as some empty function 1378 01:30:51,000 --> 01:30:53,190 because that's also something that's required. 1379 01:30:53,190 --> 01:30:55,460 And now look it. 1380 01:30:55,460 --> 01:30:56,510 It passed. 1381 01:30:56,510 --> 01:30:58,250 Yay. 1382 01:30:58,250 --> 01:31:06,460 Our first test, which is just saying the button should render, it now passed. 1383 01:31:06,460 --> 01:31:08,155 The button did in fact render. 1384 01:31:08,155 --> 01:31:12,955 And so now let's try to add one more feature. 1385 01:31:12,955 --> 01:31:21,130 Let's it correctly overrides color, the default color. 1386 01:31:21,130 --> 01:31:24,340 1387 01:31:24,340 --> 01:31:27,160 So what we want to happen is we want to be 1388 01:31:27,160 --> 01:31:30,160 able to pass a button color as a prop to the button 1389 01:31:30,160 --> 01:31:32,740 and make sure that it overwrites any default. 1390 01:31:32,740 --> 01:31:37,660 So let's do const color is red. 1391 01:31:37,660 --> 01:31:45,520 And const button is the render.create that. 1392 01:31:45,520 --> 01:31:48,171 And rather than just immediately JSONifying it, 1393 01:31:48,171 --> 01:31:49,795 let's actually grab the root component. 1394 01:31:49,795 --> 01:31:53,200 Let's grab the button out of it. 1395 01:31:53,200 --> 01:31:54,800 So let's just do .root. 1396 01:31:54,800 --> 01:31:58,430 And so if you look at the React test render docs, 1397 01:31:58,430 --> 01:32:03,911 it says you can get the instance of a class or a component by just doing 1398 01:32:03,911 --> 01:32:04,410 .root. 1399 01:32:04,410 --> 01:32:06,190 And you'll get the outer one. 1400 01:32:06,190 --> 01:32:10,780 Now we want to check the props to make sure that the color matches 1401 01:32:10,780 --> 01:32:12,500 the color that we specified. 1402 01:32:12,500 --> 01:32:17,380 And so we can do expect button.props.color.toBe-- 1403 01:32:17,380 --> 01:32:22,525 1404 01:32:22,525 --> 01:32:24,124 and what do we want it to be? 1405 01:32:24,124 --> 01:32:25,540 Well, the color that we specified. 1406 01:32:25,540 --> 01:32:32,152 And maybe here we should pass in the color is the color. 1407 01:32:32,152 --> 01:32:37,072 1408 01:32:37,072 --> 01:32:48,070 So now let's run this and expect it to fail, which it didn't. 1409 01:32:48,070 --> 01:32:56,210 1410 01:32:56,210 --> 01:32:57,650 Interesting. 1411 01:32:57,650 --> 01:33:00,301 Let me make sure I'm using it correctly. 1412 01:33:00,301 --> 01:33:10,050 1413 01:33:10,050 --> 01:33:13,721 I'm surprised it worked because it shouldn't be. 1414 01:33:13,721 --> 01:33:14,220 Let's see. 1415 01:33:14,220 --> 01:33:15,840 My button color color. 1416 01:33:15,840 --> 01:33:17,350 We passed color here. 1417 01:33:17,350 --> 01:33:19,800 It doesn't get set. 1418 01:33:19,800 --> 01:33:23,160 So this is supposedly undefined. 1419 01:33:23,160 --> 01:33:25,770 Let me just console.log the button. 1420 01:33:25,770 --> 01:33:36,040 1421 01:33:36,040 --> 01:33:46,060 Let me console.log the button's props and ensure that the color 1422 01:33:46,060 --> 01:33:47,848 is what we expect it to be. 1423 01:33:47,848 --> 01:34:00,770 1424 01:34:00,770 --> 01:34:06,324 So it's receiving color red, which is interesting. 1425 01:34:06,324 --> 01:34:13,016 1426 01:34:13,016 --> 01:34:14,520 Oh, because we don't want the root. 1427 01:34:14,520 --> 01:34:16,610 We actually want the button part of it. 1428 01:34:16,610 --> 01:34:26,390 1429 01:34:26,390 --> 01:34:29,260 So the reason that it's failing is because we're not 1430 01:34:29,260 --> 01:34:33,700 grabbing the correct part, the correct component here. 1431 01:34:33,700 --> 01:34:36,550 But since we're running low on time, I will just write it up at home 1432 01:34:36,550 --> 01:34:37,870 and post it. 1433 01:34:37,870 --> 01:34:43,040 But let me just move on so that we can get to the rest of the lecture first. 1434 01:34:43,040 --> 01:34:46,390 And so assuming that this code works, we can 1435 01:34:46,390 --> 01:34:51,040 see that by writing the tests before we write the code, 1436 01:34:51,040 --> 01:34:56,140 we can start to write a spec that allows us to then implement whatever component 1437 01:34:56,140 --> 01:35:01,880 or function we want to implement the spec that we described. 1438 01:35:01,880 --> 01:35:08,830 And so we can use integration tests like these snapshot tests here 1439 01:35:08,830 --> 01:35:12,520 to ensure that our app retains all of its features 1440 01:35:12,520 --> 01:35:16,810 and we don't break any features as we start to add new things. 1441 01:35:16,810 --> 01:35:18,190 And so how do we then-- 1442 01:35:18,190 --> 01:35:21,910 how can we tell how much of our app is actually being tested? 1443 01:35:21,910 --> 01:35:26,080 Because right now, we can kind of remember, oh, we tested Redux. 1444 01:35:26,080 --> 01:35:27,304 We tested this button. 1445 01:35:27,304 --> 01:35:28,720 We haven't really touched the app. 1446 01:35:28,720 --> 01:35:30,500 We haven't touched any screens. 1447 01:35:30,500 --> 01:35:32,440 So we can kind of keep track in our head. 1448 01:35:32,440 --> 01:35:36,800 But there's no real way for us right now to know exactly how we do that. 1449 01:35:36,800 --> 01:35:38,620 And it turns out there's actually a metric. 1450 01:35:38,620 --> 01:35:40,610 It's called code coverage. 1451 01:35:40,610 --> 01:35:44,360 And so this is a metric for tracking how well-tested an application is. 1452 01:35:44,360 --> 01:35:46,910 And there is a few different numbers. 1453 01:35:46,910 --> 01:35:50,860 One is statements, or in other words, how many statements in this program 1454 01:35:50,860 --> 01:35:52,720 have been executed? 1455 01:35:52,720 --> 01:35:54,990 Another is branches. 1456 01:35:54,990 --> 01:35:56,740 And so just like we were discussing before 1457 01:35:56,740 --> 01:36:03,100 with a couple of different possible code paths in our reducer or action, 1458 01:36:03,100 --> 01:36:05,120 this is the metric for that. 1459 01:36:05,120 --> 01:36:09,460 It's how many of the possible code paths in all of our application 1460 01:36:09,460 --> 01:36:13,210 have been executed or have been tested? 1461 01:36:13,210 --> 01:36:17,320 Another one is functions, meaning we have n functions in our app. 1462 01:36:17,320 --> 01:36:20,980 How many of them are actually tested? 1463 01:36:20,980 --> 01:36:23,360 And lastly, just straight lines of code. 1464 01:36:23,360 --> 01:36:26,230 So out of all of the lines of code in our app, how many 1465 01:36:26,230 --> 01:36:29,210 have actually been executed by our tests? 1466 01:36:29,210 --> 01:36:31,360 And so how do we get this coverage report? 1467 01:36:31,360 --> 01:36:34,090 Well, it turns out we just pass another flag to Jest. 1468 01:36:34,090 --> 01:36:40,940 We can just pass --coverage, and it will let us know all of these numbers. 1469 01:36:40,940 --> 01:36:45,310 And so we can do npm test -- 1470 01:36:45,310 --> 01:36:49,600 --coverage to pass that in. 1471 01:36:49,600 --> 01:36:55,460 And it will run all of our tests and at the very end output a table. 1472 01:36:55,460 --> 01:36:58,240 And if I zoom out so that it formats correctly, 1473 01:36:58,240 --> 01:37:00,650 we can see all of the numbers here. 1474 01:37:00,650 --> 01:37:03,850 So we can see all of the files that we've tested. 1475 01:37:03,850 --> 01:37:06,020 And so we tested api.js. 1476 01:37:06,020 --> 01:37:09,850 1477 01:37:09,850 --> 01:37:11,950 We tested MyButton.js. 1478 01:37:11,950 --> 01:37:13,030 We tested actions. 1479 01:37:13,030 --> 01:37:14,650 We tested reducer. 1480 01:37:14,650 --> 01:37:20,620 And in here, it tells us exactly how many of each metric 1481 01:37:20,620 --> 01:37:22,240 have we actually tested. 1482 01:37:22,240 --> 01:37:24,520 And so in sum.js, if you remember, it was just 1483 01:37:24,520 --> 01:37:28,180 a single function that returned with the sum of two numbers. 1484 01:37:28,180 --> 01:37:31,750 It turns out with the tests that we wrote, we hit 100% of the statements, 1485 01:37:31,750 --> 01:37:35,230 100% of the branches, 100% of the functions, and every single line, 1486 01:37:35,230 --> 01:37:36,620 as well. 1487 01:37:36,620 --> 01:37:41,265 But for the things less tested, like our reducer, just like I mentioned, 1488 01:37:41,265 --> 01:37:45,040 oh, we're going to not test the sections of the reducer. 1489 01:37:45,040 --> 01:37:47,890 We see that only 85.71% of the statements 1490 01:37:47,890 --> 01:37:51,529 are tested, which equates to 78% of the branches. 1491 01:37:51,529 --> 01:37:54,070 But every single function was tested because if you remember, 1492 01:37:54,070 --> 01:37:57,400 there was just the user reducer, the context reducer, and the reducer, 1493 01:37:57,400 --> 01:37:58,830 and maybe a merge function. 1494 01:37:58,830 --> 01:38:03,310 But we ended up invoking every single function, so 100% of those are tested. 1495 01:38:03,310 --> 01:38:07,800 But we only ended up touching 83.33% of the lines of code. 1496 01:38:07,800 --> 01:38:13,600 We can see that lines 19, 20, and 21 were not actually tested. 1497 01:38:13,600 --> 01:38:16,480 And then for the things that we really didn't test at all, 1498 01:38:16,480 --> 01:38:19,220 we see some very low numbers. 1499 01:38:19,220 --> 01:38:22,960 And so that is the code coverage report for the tests that we just wrote. 1500 01:38:22,960 --> 01:38:26,320 1501 01:38:26,320 --> 01:38:31,120 And so we've talked about unit tests and we've talked about integration tests. 1502 01:38:31,120 --> 01:38:33,250 But what about end-to-end tests? 1503 01:38:33,250 --> 01:38:36,340 And so unfortunately, currently there's no real easy way 1504 01:38:36,340 --> 01:38:39,680 to run automated end-to-end tests in React Native. 1505 01:38:39,680 --> 01:38:43,120 But there's a great work in progress by Wix. 1506 01:38:43,120 --> 01:38:46,150 And so the company Wix is writing this library 1507 01:38:46,150 --> 01:38:53,170 called Detox which actually handles end-to-end testing in React Native. 1508 01:38:53,170 --> 01:38:56,830 If you want to check it out, the github link is here. 1509 01:38:56,830 --> 01:39:02,410 There's also a github link where Brent started putting together integration 1510 01:39:02,410 --> 01:39:07,840 between Expo and Wix Detox tests. 1511 01:39:07,840 --> 01:39:11,050 But right now, it really lacks Android support. 1512 01:39:11,050 --> 01:39:15,300 And so it's not quite ready to test your apps. 1513 01:39:15,300 --> 01:39:17,770 But I encourage you to follow along with this project 1514 01:39:17,770 --> 01:39:23,100 just because it allows you to do really cool things like this. 1515 01:39:23,100 --> 01:39:27,380 And so you see here it's automatically downloading a bunch of stuff. 1516 01:39:27,380 --> 01:39:29,010 It's going to run the app. 1517 01:39:29,010 --> 01:39:32,010 And it's going to just zip through the app testing all of your features, 1518 01:39:32,010 --> 01:39:35,290 as if it were a user running the application. 1519 01:39:35,290 --> 01:39:37,890 And so this is truly end-to-end because it basically 1520 01:39:37,890 --> 01:39:43,080 simulates an end user lifting up the app and testing all of the functionality 1521 01:39:43,080 --> 01:39:43,650 very deeply. 1522 01:39:43,650 --> 01:39:46,560 And so everything, all the code that executes in order 1523 01:39:46,560 --> 01:39:55,230 to do a certain feature is executed by this Detox application. 1524 01:39:55,230 --> 01:39:57,510 And lastly, I just wanted to give some thanks 1525 01:39:57,510 --> 01:40:00,080 to everybody who's been helping out with this course, 1526 01:40:00,080 --> 01:40:03,180 to the CS50 team, including David, the production team, 1527 01:40:03,180 --> 01:40:07,891 and everybody else who just made this possible. 1528 01:40:07,891 --> 01:40:09,640 And then good luck on your final projects. 1529 01:40:09,640 --> 01:40:12,700 I'm really excited to see what you all build. 1530 01:40:12,700 --> 01:40:15,600 And thank you for joining us for this semester. 1531 01:40:15,600 --> 01:40:17,218