1 00:00:02,180 --> 00:00:07,940 I'm back in the burger project and here, I now want to add some testing. For that 2 00:00:07,940 --> 00:00:13,600 we should first make sure that npm start is not running because we need to install some additional packages 3 00:00:13,670 --> 00:00:16,870 after all we're not just using jest but also enzyme. 4 00:00:16,940 --> 00:00:22,700 Now if we have a look at our package.json file and we scroll a little bit up, we see that jest 5 00:00:22,760 --> 00:00:26,620 is indeed installed, you might have a different version but it should be installed 6 00:00:26,780 --> 00:00:27,930 but enzyme isn't. 7 00:00:28,100 --> 00:00:33,320 So let's first of all install that with npm install --save enzyme, 8 00:00:33,380 --> 00:00:35,430 now that alone won't do the trick though, 9 00:00:35,510 --> 00:00:41,830 we need to install two additional packages to make it work correctly with jest and react. 10 00:00:41,870 --> 00:00:48,820 The first is that we need to install the react test renderer package, 11 00:00:48,980 --> 00:00:55,430 that is a dependency of enzyme which we need to install separately and we need to install an adapter 12 00:00:55,440 --> 00:00:58,130 of the enzyme package to our current react 13 00:00:58,130 --> 00:01:07,310 version. So here this is the enzyme adapter-react-16 version 4 react 16. 14 00:01:07,320 --> 00:01:10,160 All these are now added to the package.json 15 00:01:10,200 --> 00:01:16,650 and of course installed in the node modules folder and once this did finish, we are ready to move on and write 16 00:01:16,650 --> 00:01:17,920 our first test. 17 00:01:17,970 --> 00:01:19,350 So here it did finish, 18 00:01:19,350 --> 00:01:26,180 now let's write our first test and I want to start with writing a test for a component because obviously in 19 00:01:26,190 --> 00:01:26,870 react, 20 00:01:26,970 --> 00:01:29,630 we talk constantly about components 21 00:01:29,670 --> 00:01:32,400 so why don't we start with testing one. 22 00:01:32,400 --> 00:01:38,640 Now let me start with a functional component here because that's of course a super easy way of testing 23 00:01:38,790 --> 00:01:42,840 and then we'll also move to containers and thereafter, to redux. 24 00:01:42,840 --> 00:01:48,450 Now I want to start with my navigation items component here, in the navigation folder in the components 25 00:01:48,450 --> 00:01:51,480 folder, that's the navigation items component, 26 00:01:51,480 --> 00:01:58,440 now keep in mind most of your react components are just functions and therefore they only depend on 27 00:01:58,440 --> 00:01:59,810 the props they receive, 28 00:01:59,850 --> 00:02:02,800 that's something you have to keep in mind for testing. 29 00:02:02,820 --> 00:02:05,950 Now let's create a testing file for this component, 30 00:02:05,950 --> 00:02:13,200 therefore next to it in the same folder, I'll add a new file which I'll name NavigationItems.test.js 31 00:02:13,350 --> 00:02:21,300 the .test.js is important because that is automatically picked up by create react 32 00:02:21,340 --> 00:02:22,110 app once 33 00:02:22,110 --> 00:02:28,260 we run a special command and will then be included in the testing and therefore will be tested. 34 00:02:28,260 --> 00:02:36,750 Now inside this test file, I now can start writing my test and a test uses just by default and just on 35 00:02:36,750 --> 00:02:41,040 the other hand gives us a couple of methods to define the test. 36 00:02:41,280 --> 00:02:44,800 The first important method is the describe method, 37 00:02:44,850 --> 00:02:47,130 you don't need to import it in that file, 38 00:02:47,130 --> 00:02:51,870 it will automatically be made available in our create react app project 39 00:02:51,870 --> 00:02:59,070 once we run the test command. Describe is a function that takes two arguments, the first is just a description 40 00:02:59,070 --> 00:03:01,740 of the test bundle 41 00:03:01,740 --> 00:03:03,110 this file holds 42 00:03:03,300 --> 00:03:09,630 so here I'll simply name this NavigationItems and I'm writing it like a jsx element but that's not required. 43 00:03:09,840 --> 00:03:13,040 This is only what you'll see later in the console output 44 00:03:13,080 --> 00:03:17,790 so it should be something which allows you to identify which kind of tests we'll run here. 45 00:03:17,850 --> 00:03:22,980 The more interesting part comes in a second argument, that is your testing function. 46 00:03:22,980 --> 00:03:28,620 It's a normal javascript function and I'll use an ES6 arrow function here, in here you're going to 47 00:03:28,620 --> 00:03:32,850 describe, you're going to write your actual tests. Now to do that, 48 00:03:32,880 --> 00:03:35,470 you write a test by writing it, 49 00:03:35,580 --> 00:03:38,760 that's another function which will just be available. 50 00:03:38,880 --> 00:03:43,590 It describes or allows you to write one individual test, 51 00:03:43,620 --> 00:03:45,630 it also takes two arguments. 52 00:03:45,750 --> 00:03:50,960 The first one is again just a string, a description which will appear in the console 53 00:03:51,240 --> 00:03:56,270 and typically you just complete the sentence so it and then you describe what it should do. 54 00:03:56,280 --> 00:03:59,030 So it should 55 00:03:59,040 --> 00:04:01,580 and now let's look into our NavigationItems component, 56 00:04:01,770 --> 00:04:09,660 let's say by default if we're unauthenticated, this component should render one navigation item, 57 00:04:10,290 --> 00:04:15,590 the second one should not be rendered and that here it should render one more leading to /auth, 58 00:04:15,810 --> 00:04:18,560 so it should render to navigation items 59 00:04:18,630 --> 00:04:20,830 if we are not authenticated. 60 00:04:21,240 --> 00:04:24,240 So that is what we want to test so let's write the sentence, 61 00:04:24,240 --> 00:04:32,700 it should render to navigation item elements if not authenticated. 62 00:04:33,090 --> 00:04:36,510 So this is just my description and it doesn't matter what you write here, 63 00:04:36,510 --> 00:04:41,870 this is not parsed or anything like that, it should just be something meaningful you recognize in a 64 00:04:41,860 --> 00:04:46,140 console because if the test fails, you want to know which test failed. 65 00:04:46,590 --> 00:04:49,070 So that's the first argument to the it function, 66 00:04:49,080 --> 00:04:56,610 the second argument is now again a testing function describing the actual test, here that is just a normal 67 00:04:56,610 --> 00:04:57,660 javascript function 68 00:04:57,660 --> 00:05:03,130 I'm again going to use an arrow function and in here, we write our actual testing logic. 69 00:05:03,390 --> 00:05:10,620 Now what we want to do is we want to create an instance of this component as it would be rendered to 70 00:05:10,620 --> 00:05:17,250 the dom, to the real dom through react and then have a look into the rendered component and see what 71 00:05:17,250 --> 00:05:22,920 was rendered for the case that the isAuthenticated prop is false. 72 00:05:22,920 --> 00:05:28,770 Now you might think that for this, we obviously need to render the entire react application because 73 00:05:28,770 --> 00:05:35,520 navigation items is just one tiny piece in the entire react application, that is where an enzyme comes 74 00:05:35,520 --> 00:05:43,800 in, this testing package. Enzyme allows us to just render this navigation items component standalone independent 75 00:05:43,800 --> 00:05:46,210 of the entire other react application, 76 00:05:46,320 --> 00:05:52,980 that's the whole idea behind the enzyme package, that we can really write unit tests, isolated tests, tests 77 00:05:52,980 --> 00:05:56,350 where we don't need to render the complete react app. 78 00:05:56,580 --> 00:06:04,120 So let's import enzyme then, I need to import something from enzyme, now I'll come back 79 00:06:04,150 --> 00:06:04,970 to that something 80 00:06:04,970 --> 00:06:12,040 but first I'll also need to configure enzyme and connect it to my react version. For that, 81 00:06:12,050 --> 00:06:17,950 I need to import the adapter and it's a default export so you you may name this whatever you want. 82 00:06:18,050 --> 00:06:25,820 The adapter from enzyme adapter react 16, this package and from the enzyme package, we now only need to 83 00:06:25,820 --> 00:06:27,220 import something specific, 84 00:06:27,230 --> 00:06:28,580 this is a named export 85 00:06:28,580 --> 00:06:34,260 so we need curly braces, the configure function. With these two imports added 86 00:06:34,260 --> 00:06:41,120 here above the described function, we can now execute configure and pass a javascript object to configure. 87 00:06:41,270 --> 00:06:47,990 There we should set up an adapter property and assign new adapter as a constructor function, 88 00:06:47,990 --> 00:06:54,820 so this adapter is instantiated with new adapter and that's all, with that enzyme is connected. 89 00:06:55,250 --> 00:07:01,760 Now we want to render a navigation items component and then look into it, for this enzyme gives us a 90 00:07:01,760 --> 00:07:04,660 specific helper method we can use, 91 00:07:04,840 --> 00:07:06,140 we import that too, 92 00:07:06,290 --> 00:07:12,820 it's the shallow function. Shallow is the most popular or the best way of rendering react components 93 00:07:12,830 --> 00:07:14,860 in many circumstances, 94 00:07:14,970 --> 00:07:20,510 enzyme offers two alternatives which I'll also point you to later but shallow is the one you should 95 00:07:20,510 --> 00:07:28,210 use as often as possible because one thing shallow does is it renders the component with all its content 96 00:07:28,640 --> 00:07:31,750 but the content isn't deeply rendered. 97 00:07:31,850 --> 00:07:39,860 So the navigation items component here has navigation item components but these are only rendered as 98 00:07:39,860 --> 00:07:40,840 placeholders, 99 00:07:40,970 --> 00:07:46,430 the content of them isn't rendered and that of course again is important for creating isolated tests 100 00:07:46,490 --> 00:07:50,080 where we don't then render a whole sub tree of components, 101 00:07:50,180 --> 00:07:55,520 we just want to render this component and know what's inside of it without rendering everything which 102 00:07:55,520 --> 00:07:58,460 is nested inside its included components. 103 00:07:58,700 --> 00:08:01,540 So shallow is the method to use here 104 00:08:01,880 --> 00:08:06,970 and now, we want to render that. So I'll create a constant which I'll name wrapper, 105 00:08:06,990 --> 00:08:09,590 the name is up to you but wrapper is often used, 106 00:08:09,830 --> 00:08:16,020 where I will call a shallow and now I'll pass navigation items as a react element. 107 00:08:16,460 --> 00:08:23,510 So for that, I first of all need to import this, I need to import navigation items from 108 00:08:23,510 --> 00:08:29,360 and that is from the navigation items javascript file which is living next to our navigationstest. 109 00:08:29,390 --> 00:08:30,660 javascript trip. 110 00:08:30,910 --> 00:08:34,240 With that we can render this here as jsx 111 00:08:34,250 --> 00:08:35,110 and that's important, 112 00:08:35,110 --> 00:08:39,360 we pass jsx to the shallow method. For this to work, 113 00:08:39,380 --> 00:08:46,070 as always we of course need to import react then because no matter if it's a test or not, the jsx 114 00:08:46,070 --> 00:08:51,270 code needs to be converted to its react create element alternative. 115 00:08:51,290 --> 00:08:56,780 So now we're shallowly rendering this and we're storing the result in this wrapper constant, 116 00:08:56,780 --> 00:09:02,770 now we can have a look into the wrapper in this test. And that's the last part of testing, we now 117 00:09:02,810 --> 00:09:10,880 our expectation, for that we use another method which is made globally available by jest, the expect method. 118 00:09:10,880 --> 00:09:15,370 Inside expect, we define our, the thing we want to check 119 00:09:15,650 --> 00:09:19,890 so here I want to check if the wrapper contains a certain element. 120 00:09:20,210 --> 00:09:27,180 Now on the wrapper, we can again use a utility function provided by enzyme defined method, 121 00:09:27,400 --> 00:09:31,790 this allows us to look into the wrapper and see if it contains a certain content 122 00:09:31,790 --> 00:09:34,580 and here I want to find a navigation item. 123 00:09:34,760 --> 00:09:43,250 So we need to import this too, I'll import navigation item from ./navigation item navigation item, 124 00:09:43,340 --> 00:09:50,830 just like that and therefore here in the find method, I now want to find navigation item. Important, 125 00:09:50,930 --> 00:09:58,260 this now is not a jsx element, it's this normal exported function from the navigation item file. 126 00:09:59,290 --> 00:10:00,220 Now with that 127 00:10:00,250 --> 00:10:02,390 imported, we expect 128 00:10:02,410 --> 00:10:04,270 well we expect nothing right now, 129 00:10:04,420 --> 00:10:08,250 we just say what is our thing we want to check, 130 00:10:08,250 --> 00:10:13,360 we want to check if we find that, but what is our expectation then? You could say the expectation is that 131 00:10:13,360 --> 00:10:14,360 we do find it 132 00:10:14,470 --> 00:10:16,750 but tests are a bit more flexible than this. 133 00:10:16,900 --> 00:10:21,820 You could expect that you'll find it only once or twice or that you don't find it, maybe you want to 134 00:10:21,820 --> 00:10:23,530 test for the opposite 135 00:10:23,530 --> 00:10:26,750 so here we have to change something to the expect call, 136 00:10:26,980 --> 00:10:34,840 these are utility methods made available by jest. So we can expect to find the navigation item 137 00:10:34,840 --> 00:10:42,250 as we said earlier, two times if we're not authenticated, so navigation item to half length is what we can 138 00:10:42,250 --> 00:10:43,170 call now 139 00:10:43,390 --> 00:10:45,540 and you see there are a couple of helper methods. 140 00:10:45,670 --> 00:10:47,870 The length we expect to find is two, 141 00:10:47,890 --> 00:10:49,210 we want to find two 142 00:10:49,360 --> 00:10:51,420 so this is automatically added into an array 143 00:10:51,520 --> 00:10:54,260 and we want to have this to have a length of 2. 144 00:10:54,460 --> 00:11:02,070 Now it will have isAuthenticated set to false because we're not passing this prop, remember? We're 145 00:11:02,060 --> 00:11:06,400 just shallowly rendering navigation items, we're not sending any props here. 146 00:11:06,430 --> 00:11:12,670 Now if we render it like this, isAuthenticated is not passed and therefore will be treated as false. 147 00:11:12,820 --> 00:11:15,790 So with that, this test should actually succeed. 148 00:11:16,120 --> 00:11:18,930 Now let's find out how we can test it then. 149 00:11:19,180 --> 00:11:21,150 For this let's have a look at the package.json 150 00:11:21,180 --> 00:11:27,220 file and there, if we scroll all the way to the bottom a little, not all the way excuse me a little 151 00:11:27,220 --> 00:11:28,740 bit below our dependencies, 152 00:11:28,930 --> 00:11:30,800 we see the scripts section. 153 00:11:31,060 --> 00:11:32,380 We know the start script, 154 00:11:32,380 --> 00:11:33,720 this runs in the browser, 155 00:11:33,790 --> 00:11:35,710 we'll see the build script soon, 156 00:11:35,710 --> 00:11:43,670 now we need the test script. And we can run this with npm run test or just npm test actually, like start 157 00:11:43,690 --> 00:11:46,720 it's a special script where we don't need to run command. 158 00:11:46,950 --> 00:11:52,810 This will now execute all the tests and it will automatically scan for all tests files by looking at 159 00:11:52,810 --> 00:11:54,780 the ending, test.js. 160 00:11:54,980 --> 00:11:58,430 Now I never save this file, so I should do so now, 161 00:11:58,450 --> 00:12:00,790 this will then automatically rerun our tests, 162 00:12:00,790 --> 00:12:02,370 it's watching the test files. 163 00:12:02,710 --> 00:12:05,480 This warning regarding the polyfill can be ignored, 164 00:12:05,710 --> 00:12:13,840 more interesting is if I expand this that we have one passed tests suite, the tests suite is the described function 165 00:12:14,260 --> 00:12:16,900 and one passed test in general, 166 00:12:16,900 --> 00:12:19,930 that's the it test here, the it function. 167 00:12:20,000 --> 00:12:23,240 So our test is passed as we have expected 168 00:12:23,380 --> 00:12:26,860 and this is how we write a test for a component. 169 00:12:26,860 --> 00:12:32,570 Now let's add some additional tests to this component before we then also dive into testing other things.