How to Test In React - React Testing Library + Jest Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey guys how's it going i'm back here with another video and today i decided to bring this video where i'm going to be going over unit testing and react so i know this is a topic that i've talked about in the past it's i actually made a video on it um on how to work with the react testing library it was really well received and for that reason i decided to make another one which goes more in depth shows more like in real life examples and i just overall explain it better unit testing is something that a lot of people don't like i know how it is like people don't find it as useful especially in the beginning however it is extremely important to maintain your code well organized and also it helps you find bugs like 100 studies have shown that uh it actually decreases the time it takes for you to find bugs by almost 80 percent um i'm not sure how reliable those studies are however i just know that overall if you've been testing for a while you'll realize how important it actually is and how much it helps in the long run and for most people they just want to learn testing because you will need to do unit testing in every single job most jobs want to maintain their code very we want to maintain a good code coverage i want to test everything in order to prevent some bugs or errors from occurring so it is definitely important for the developers to continuously test their code even if it seems redundant because sometimes it does um many people will eventually have to do this so it's nice to have this skill and in react there is two three libraries uh but two different combinations of those three libraries which are very commonly used so the first one is a combination between the react testing library and uh jest so you can see that when we open up a react application and i'll go over what this react application is that i've already built over here but basically if you open up an application and go to your package.json you'll see that it usually when you run create react tab it will come with this over here so the react testing library um and includes uh jest as well so this is a standard combination and it is the one we're going to be using in this video however if you guys are interested in seeing a video where i use enzyme instead of react testing library um i can definitely do that too it's also a very famous combination and all the libraries existing are well maintained and works pretty well so in order to make this video more intuitive i built this simple react application that will cover most of the different aspects from testing so you can see right here we have a very simple web app um it is it exists inside of our app.js and it renders two different components as you can see over here one component called input and one component called button so in the front end when you see the website this is what you see it's an input and when you type on this input a text will appear showing whatever you're typing right um and also when you click over here you'll see another button will appear those are the two different things and there's also this thing over here which is saying hey my name is pedro um please subscribe i would be very very happy please um if you come over here to your component uh in the app.js there's a state if you set this equal to false you'll see that this won't show so why did i do this well i know this this web app is like it makes no sense uh it definitely doesn't like why would someone make this however it definitely shows the different aspects that are important to learn and the different skills that you need to execute when you're testing your application the first skill that we need to execute is the fact that we have a button so i'm gonna write some tests for this button component the button component is this over here you can see it's very very simple all it has is a state called show another button it is set to false and when you click on the button it just set show another button to true so it basically shows the the button right this is the logic for showing the button so when we click on the button it will show another another button and you can clearly see right now that i added some some some properties to our our tags which you might find weird if you're not used to testing so what happens is when you're testing you need to actually grab the individual elements inside of your component so a way to differentiate them is by adding this property right here which is data test id you can do this in many different ways um i like using using data test id people may say that like oh it's you can see it in the front and i don't think it's that big of a deal however do your own research on this case you can search it by so many things you can search by role you can search it by um i don't know title you can search an input by how however way you want to um i like using this text to differentiate the the actual elements and in this case i gave the the test id of button for both of them for a particular reason so if you go to the input you'll see that we have uh another component this component is a little bit different we have a prop being passed called show div we have a state inside of here and we have an input in the input if you search on the input it will basically change the state called search word to be equal to whatever you write on that input and over here it just displays that actual state so this is what's happening right here when you're right here it shows what we're writing and over here at the bottom we have this thing where if if the prop show div is equal to true then we display the div as as i mentioned before now the test ids that i put over here are different you can see that for the search bar it's or for the input it's it's search bar and for the david's div we want to show and this is also display search normally you want to give a different one for each element in order to differentiate them there's a reason why i did it for the button and you guys will see in a bit so now that we have our components already built we already know and understand how they work how do we test this logic so the first test that i'm actually going to write is for the input.js not the button i'll get to the button in a bit so for the input we got to really think about what we want to test and how can we actually test it so to create a test file you just go here to your components file or wherever you have your your actual component and you create a compo a new file which has the same name as your component so input then dot test dot js and the reason why we put the test is because when we run a certain command in our command line um react will automatically check for all the files with this extension and run the tasks on all of them so it is necessary that we put this little extension.test because it will eventually help us when we're running our tests so over here we can write all the tasks that we want but we really need to think about what we want to test so in this component we see we have some ui stuff we have some logic what are the things we want to test well i'm thinking right off the bat the first thing i want to test is whether or not this input shows right if this inputs render when we render this component we want to make sure that this over here is also rendered because if it isn't then we're basically rendering an input component without an actual input inside of it and the second thing we want to test is if i write on this input what will happen here right we want to test to see if i write on this input the text inside of this h1 will be equal to whatever we wrote inside of this input and this is important because this is testing logic we're testing to see if our state as our state changes uh our actual application will update accordingly and finally we want to test to see if i pass this component with a with a value for its prop which is false uh we want to test to see if that this doesn't show up but if it's true we're going to test to see if this shows up and it will become clearer as we write our tests so let's start doing it okay so in this file the first thing we want to do is we want to import some stuff from the testing library so we're going to say import from um at testing library react and what we want to render or what we want to import for now is first of all just to render uh the render function over here we're going to import more stuff but as we go i'll keep importing then we want to import our actual input so to do that we're going to come over here and say import and we want to import a component called input from uh dot slash input over here so we need to import our actual component that we're testing and now that we have that done we already basically have all the functionality that we need um to actually start a an actual testing site um there's many ways you can do it what i like to do is i like to describe use the describe keyword which basically allows you to describe a whole test case so you're testing this component so forever component i just describe what i'm doing so let's call it input component text a test this isn't for the this one won't do anything to your actual test all it does is it organizes your stat your tests so that you know that um this is the test for the whole input component and everything individually inside of that component will be inside of this describe so the actual test will run whenever you use either one of these two keywords when you use the test keyword or the it keyword i like to use the it keyword um i don't know why i just use it uh i'm just used to using it a lot of people use it as well so this is what i'm going to be using it in this tutorial so when you use the it com the 8 keyword basically you're describing a certain event inside of this component so the first thing we want to test is if there is uh if it rendered the actual input so what we want to do is we're going to say let's call this test rendered input so this is just a name for the test and then we pass a function over here which is going to write the logic for testing this actual logic so how do we test if it actually rendered the input so there's a function in in the react testing library which is the render function which is what we imported over here and you use it to actually render the input as a as a mock of the input so we're going to come over here and say const and set it equal to render and we just pass over here the actual input that we're testing so i'll just say input like this and you don't need to pass the props i know that input has props you can pass it if you want to well let's just do it right now let's pass the prop show div and let's just set it equal to false it doesn't really matter because this test is specifically it's just testing to see if this input appears so now what we're going to do is we want to grab from this render some sort of identifier some sort of function that will help us grab the elements inside of this component and this is what i'm talking about there's many functions you can grab from here but the one we're going to be using is the get by test id and you can grab by many things this is just a way to identify which elements inside of this component you're trying to access and trying to test so when we say get by test id i can access a certain element inside of here by just saying something like uh let's just let's just grab the input and say something like x constant input equals to get by test id and pass the test id for this input so i'll pass the search bar over here and i'll just put a a string as well and now we actually grabbed the input inside of the component and what we want to test here is we want to test to see if this actually appears and whenever you want to assert something or you want to test something to be true or not you use the expect keyword like this and over here inside of this expect function you put what you're going to test so like in this case we're going to put the input inside of here so i expect that this input will be something right and we can we can we can test many things but in this case we just want to test to see if that input appears so the way we test that is we can use the 2b truthy uh function and this all it does is it just says true or false whether or not this appears in the in the actual dom so in this case uh this should run and and work out and we're going to test it right now so when you have a test like this as a as i told you guys it will basically go over all your application and search for uh dot test files so to run every single test in this in our project we just say yarn or if you're using npm you can use npm and then use test that's the command we run and when i click this you'll see it will start searching for every single file in our case just one of them and it should start testing for that file specifically and as you can see the test has passed um if we did something weird like instead of saying that we expected it to be true we said that we expected it to be falsy which is basically the opposite um it wouldn't have run you can see it will say it's it failed the test and one thing that's interesting as well is when you run the yarn test command um it will keep running as long as you save the file so um i can change this just save the file and it will automatically run again you need to run the command multiple times so what i want to do now is i want to start testing more logical stuff so for example i want to test this c if we uh render this component with a different prop so if the prop is true i want to show the div if i if the prop is false i don't want to show this div right here so the way to do this is we're going to come over here and we're going to create two different tests i'm going to say it and this test will be render div and it's going to be very similar to the other one that we made um like this um and then we need to just close this and then we're going to create another test which is don't render the div or yeah let's just say don't render div something like that and both of these tests will be very similar the difference is that we're going to be passing different props to our component so i'm going to grab this over here and i'm going to say okay the first one is we want to render the dip so we're going to pass the prop as true and we're going to grab by id and what we want to do is we want to grab the div let's call it div equals to get by test id and the test id that we put in our div is the div we want to show so we just grabbed this over here we identified that this is the the actual element that we're talking about and at the end and we can just say that we expect uh the div that we try to get to be truthy as well like this because we passed the the prop is true so it must render this div you can see that if we save this it will automatically run the test again and you can see that now it says three pass one test suit because this is a test suit and there's only one but in individual tests three has passed and the reason why three has passed is because we haven't put anything here yet so it automatically assumes that it passed but the good thing we know is that none of them failed so this one also passed now let's test the fact that if we pass a a prop which is false um it shouldn't render the div so let's just come over here and do the same thing but now pass this false and grab the same div but instead of being truthy we need to see if it is falsy and if we run this it should still say that it passed but it says it didn't pass and let's see what's the problem with this um it said that get test by id didn't work and i know why it didn't work in this case specifically we need to know that sometimes it shouldn't actually appear right because normally when you look at the input in itself it's there's no elements with this certain test id so in this case we want to use a different function which is the query by test id um and if we use this instead of the get by test id it should actually work as you can see it passed because we can't when we use the get by test id it only works for elements that specifically are already pre-rendered when you render the component it will pre-render into the dom and in this case over here since it is gated by a state it won't work with the get by test id so we need to use the query by test id again if you want to look at all the functions that you can use um from jest to actually query stuff to get stuff um there's many different resources online i'm gonna definitely put a link in the description where you can look at the documentation um you can use whichever one you you want and it's very easy to read so i would definitely recommend so now that we actually tested uh the logic for the prompts and we tested to see if the input is actually rendering let's do the final test which is probably the most important one we want to test to see if we're right on this input if we fire an event where we're right on this input we want to see if this h1 tag over here will actually display the actual word in which which we wrote in this input so to do that we're going to come over here create a new test and let's say um change on input causes change on header and i call it like this because uh we want to say that when we change something inside of the input when we write on the input we'll change the value from this header over here so let's just pass the function like this and one thing that is important to understand is whenever you're dealing with something that will change an individual state from the application and in this case it would be because uh we created the state over here and when we modify the state we want our application to modify together with us so when we are dealing with a situation like this you actually need to wrap your test around with an act function like this and this is extremely important because if you don't then it won't re-render the actual component that you're trying to render if there's a change in the state which means that you won't be able to see the change in the state so whenever you're changing something individually inside of your component a state that exists inside of your component so it wouldn't be true in this case over here because the state 4 show div it's it's not inside of the input component it is it's outside of it it's in the app.js so if you have a state that is inside of the component and it will change throughout the test you need to wrap it around with this act function so instead of this ag function what we want to do is we want to first of all get by id again uh we're going to get by test id instead of rendering or querying like this and we just want to grab the input as a whole right so what we want to do is we want to use this get by id by to get our input so i'm going to say const input equals to the same thing that we did over here just grab the search bar um and now what we're going to do is we want to use a function from the react testing library which is the fire event function and this over here allows you to simulate events inside of your application which is amazing because we want to simulate a person writing on this input so to simulate it all we have to do is we have to fire an event and then say dot change because it is a change event and right over here we pass two different properties first of all the element that we're trying to change so the input and then we have to write a little bit of syntax that looks a little bit of like a little bit weird but all we're doing is we're modifying certain aspects of this input so each input has a target right so we can say that we want to modify the target like this and instead of the target each input has a value and that value will represent the the actual value inside of the input so what is currently written inside of the input so all we have to do is we want to modify the input and modify its target and modify inside of that target its value to be equal to something so let's create a variable over here uh let's just say we want to modify we want to write uh my name so uh let me say input word and let's put pedro so all we're doing is we want to say that we want to simulate someone writing pedro inside of this input so i'm just going to put the variable over here and now what we want to do is we want to expect that since someone wrote that inside of the input we want to expect that the header will now contain the same word so the same input word inside of it but we haven't grabbed the the actual header yet so what i'm going to do is i'm going to grab over here and we're also going to grab the header not only the input but we're going to grab the header and the actual tag for the header is display search as you can see over here we're going to put it inside of here and now we have access to both of them so what i want to do is i want to say expect header dot and then when you put a dot you can access individual properties from every html element for example if i have a header like this one over here and i want to access um the like the text that is inside of this header i can very easily do that by just accessing its inner html like this so this will represent the actual text inside of the header so if we want to compare it we want to expect it to be equal to the actual input word because that's what we're typing on our input now i like on purpose i don't know if you guys realize but on purpose i i left a little bit a little bug that i'll show you guys when you run this if i save this over here first of all you'll see it won't pass it will say that it received nothing when it was expected to receive pedro because pedro is the input word that we put the reason for that is because we need to take into account that uh we wanted this to be done before this is executed and currently this is not happening so this means that we need to make all of this asynchronous so to do this we just come over here we turn this function asynchronous and we just say that before we continue to move here we want to wait for the event to be executed and if i save this now you'll see that it should actually actually pass the tests it will give us this warning over here and if you want to fix this warning you just have to make the it function over here also asynchronous and a wait for the for the act to be done so when you save this you'll see that it will still pass and uh actually it won't pass and this is the bug that i left for you guys it won't pass because of the following reason so you can see over here it's saying that it expected pedro but it received pedro but with the space in front of it and the reason for that is because um i did leave this space over here and the reason for that is if you are going to test do unit testing make sure you know exactly what you're doing this space could have meant a little padding or a little bit of space in my front end so you need to really be sure of what you're actually writing and this kind of minor errors are easily overlooked when you're not unit testing like this so when i save it you can see clearly it works all the tests have passed because it knows exactly what's happening and we're simulating the component in a correct way so now this is pretty much it for this input component we we tested most of it we tested the ui that everything is rendering completely we tested that the props actually have an effect on it by uh showing the div or not showing the div and finally we tested its individual logic by using its states and also uh triggering uh events such as a change in the input now we want to write some tests for the button so i want to create a new file over here called button.test.js and honestly i'll just copy everything that we wrote here in our input and i'll just paste them over here but we're going to obviously change everything because uh we're writing tests for the button first thing we want to change is we want to import the button instead of the input over here like this and now uh we also want to change this to be the button component that's the name that we're describing that's the test suit that we're running and one thing that we want to realize is we really need to stop and think what do we want to test so the first thing i want to test is um let me just open up the component i want to test that this button actually renders so i just want to see if this renders if it doesn't then clearly there's something wrong in our application so to do that very simply we'll just say rendered button i will get by id will render the button instead of the input component and this button component doesn't have any props so let's just delete this and we passed the data test id for the button and we called it button so i'll just copy this paste it over here and we're just expecting the button to be truthy and this should run uh perfectly right let me just copy this over here and paste it over here i'm gonna delete all of this because this doesn't make any sense at least in this context but you can see that everything should be working and if i run this you can see we have now two test suits because now we have the button component test suit and the input component test suit and every test inside of it passed completely which is great but the next test which is the problem the last task we're going to be running is we're going to be trying to trigger and a click on the button and you can see that when we click on the button it just renders another button very like almost the same thing it's the exact same button just doesn't have another click event as you can see um and why are we doing it this way is because you can actually check and query for all the buttons inside of your application and you can do that for every single element you can crack for all the inputs you can query for all the divs all the header tags all the you like every single element possible and you can arrange them in this in an array and you can check to see the length of the that array specifically which means you're checking to see how many buttons are in that component which is something that you might want to do in many different situations so what i want to test is that when i click on this button like initially before i click on the button there should be only one button in the component so i'm gonna check for the length of all the buttons and it should be one but when i click on it it should update and show that the length of all the buttons is two because now there's two buttons in our screen so let's test to see if this is working i'll come over here and i'll just say that uh creating your test let's say it and let's say uh render uh one button before button click something like that uh i know that i like the the name is horrible i'm horrible with giving names but uh let's just create this test and all we want to do is we want to first of all just check to see how many buttons are in the screen so when you render the component before you actually click on the button we're going to use this function from the renderer so let's say const equal to render and let's render the button uh like this and we want to use this function called query uh or not actually not sorry let's not use query let's just use get all by test id so the difference between get all by test id and get by test the d is just that this one will get every element with the same test id and you can see that we actually gave the same test today for both of them um and the other one will just get one similar to get all elements by id a normal javascript and just get element by id yeah this one will return an array even if there's only one element it will return an array with all the elements with this specific test id so what we're going to do is we're going to create something over here called button list and say that we want to get all by test id and pass the test id that we're trying to grab which is the the button one and finally we want to say that we expect the button list like this and then we can use this function which is the to have length like this uh to have length yeah to have length and we can put a certain value over here so the length will be one because right now when you render the component it should only have one button let's save this and let's check to see if this is actually true let's open this and you can see that now our last our our new test passed and it's working perfectly now let's simulate a button click and check to see if the length it becomes two so let's copy this over here paste it over here change this to render two buttons before after button click and now what we wanna do is we wanna grab all the elements all the buttons right and we wanna again uh simulate uh an event that triggers a state so you can see that we have a state over here which is this one over here and every time you wanna trigger a state every time you wanna change a state you want to wrap all this around with an act function and i mentioned this before so we have to do it again we're going to wrap all of this with uh with the act and now all the change in state will be replicated in the test so what we have to do before we expect anything is we want to fire the event so i want to fire an event which is um a click event so i want to click on something and the thing that i want to click is the actual button but the first button so initially as you recall this should return a list um but the thing is initially before we click on anything it should only have one button so we're gonna say that we want to grab the first button in the list and we're going to click on that one which is the actual button which triggers the state change and it shows the other button so when we do this we expect the button list to have length 2 and this is not completely right and i hope you guys noticed the error because you'll see it won't pass you see it doesn't pass it actually doesn't like it doesn't work at all it says the button is not defined uh actually button is not defined because i need to call it button list but it will still fail and you'll see why um over here it will say that it doesn't have length two it has length one and why is that happening well because we need to make this asynchronous why because when we click on this button this is being executed before the state change so it still has one button so we need to make this over here an async function make this a weight and then make this async like we did before and make this a weight as well like this and finally before we run the test to see if it works there's a final bug that i left here which is um think about it this way this over here will grab all the buttons that exist in the on the dom right now so it doesn't include the second one then we wait for the event to happen and then we check to see if that same list has a length of two why would it have a length of two it's a constant right it doesn't change based on this what we have to do is we just have to grab all the buttons again and check to see if it has a length of two this over here was the old but the old size the old list it won't change automatically but if we try to get everything again now it will have the updated value so if we opened up this we run this you should see that now everything has passed seven tests has passed and we actually successfully um were able to write some tests for two components it is pretty fast i know it's annoying to write tests but it definitely helps out and as you do more of them it definitely gets quicker i remember spent the first like first time i wrote test was for my startup job and it took me like two days to figure out like how to write a test for a small component because i was trying to do crazy stuff like i was trying to test like every single aspect of the component which isn't like what you need to like obviously the more tests you write the better the more code coverage but like don't waste your time completely on it spend your time writing tests for the most important aspects of the component and then move on if you write your tests and you don't find any errors there is likely no errors in your component but if there is a major error in your component and you write tests correctly you'll definitely find that error while you're writing your tests so that's basically it i really hope you guys enjoyed this video if you enjoyed it please like down below your comment what you want to see next subscribe because i'm posting two to three times a week and i would massively appreciate it my membership program down in the description i launched this last week and i'm really excited so yeah that's that's basically it i really hope you guys enjoyed it and i see you guys
Info
Channel: PedroTech
Views: 3,746
Rating: 4.9784946 out of 5
Keywords: crud, css, javascript, learn reactjs, reactjs, reactjs beginner, reactjs tutorial, typescript, react js crash course, react js, node js, express js, pedrotech, traversy media, traversymedia, clever programmer, tech with tim, freecodecamp, deved, pedro tech, react testing library, react testing library tutorial, react testing with jest, rtl tutorial, jest tutorial, jest tutorial react, how to test in react, react testing, reactjs testing, reactjs testing with jest tutorial
Id: Vp_76zdHkV8
Channel Id: undefined
Length: 31min 46sec (1906 seconds)
Published: Mon Jun 28 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.