Test React components with React Testing library & Jest

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to my react testing library and jazz tutorial in this tutorial we are going to learn how to test some basic functionalities of the web apps that's built with react here is a short summary of what we are going to build we are going to have a list of data from the server and we are going to test that data is fetched correctly another feature will be to create a new post and that will actually trigger a fetch method to the server and it will add a post to the end of the list so i will start by creating a project with create react app and i will copy and paste this command in the documentation so i will speed it up a little bit and now our project is ready so let's drag and drop project into visual studio code and i will open a terminal and run npm run start and that will run our app in the browser let's remove this existing template and start with implementing our functionalities i will remove the this whole section and i will also remove a class name because we are not going to use css i will create a new folder components where i'm going to create also folder posts and inside this folder i will create posts js component which will be in charge for everything that we are going to build first line of every react component is importing react and i will declare posts component function that will return div with posts text and i will export this component as default i will import posts component into app js and now posts text should be visible so let's switch to posts component and i would like to put this text in h1 element so it will be header of this component and below that i will create unordered list and here i would like to iterate through data of posts and in order to get that data i will go to jsonplaceholder api that is a fake api that provide us some endpoints that we can use for testing and i will use this getposts endpoint i will just copy this link into our component for now i will use use effect react hook in order to fetch this data and this use effect will have empty array as dependency because i want to call it only once and i will use fetch method with this endpoint and then i will provide then callback that will return json and another then callback that will return actual data and for now i would like to console.log this data just to check that everything works fine let's go to the browser and see in our browser's console posts data so we have array of 100 posts and that is great but now i would like to store that data in some variable and i will actually use use state and create a component state for that it will be an empty array by default and i will use setposts method to update the state now i can iterate through these posts because data is stored inside i will use map function to iterate through posts and i will have post and index parameters for each post i would like to return ally element with post title and don't forget to add key property to each item so we have a list of posts in the browser and i would like to adapt a template a little bit i will wrap this post title with h3 tags and for the post body i will use paragraph so now we have both title and body displayed for each post now i would like to write a test for this component functionality and i will create a posts dot test.js file inside the components folder first thing that i'm going to do is to create describe function that will group all tests that are related to this component first test that i'm going to write will check if the browser fetch and renders data from the server so i will call it fetch and render posts and here is a callback function that will be executed first i'm going to render both component and i will import render function from testing library and as a parameter i will provide posts component so let's start our tests with npm run test command we have one failed test and it is inside app.test.js file it is something that we should remove because we removed the template that we get from create react app and it should work fine now yeah both tests pass so the thing that i want to check in this test is that this post component will fetch data from the server and display it correctly in the dom in order to do that we will need to mock fetch method inside the test and what does that mean before running each test i would like to create a mock for the fetch method so when we trigger render method and inside the component we have a fetch method that will actually execute this function that we provide to just fn as a callback so inside this callback i would like to return just promise resolve for now now we have an error which says cannot read property json of undefined and that's because we're just returning the empty promise resolve we are going to return an object with json property and that json should return another function that will return promise resolve and inside that we are going to put some post data so i'm going to create a variable where i will put some post data that i would like to use as a response from the server and i will just copy this part of array and now i will put this data into promis resolve so now when we run test and render post component calling this fetch method will actually return this data as a response from the server we have an error and let's see what it is it says that we should wrap our component into act method this error occurs when we have updates of component state along with asynchronous code so we will also need to put async and the weight in front of the functions and let's refresh it again all tests are green now so let's check that these posts are rendered correctly in the dom and in order to check that i will use screen api from react testing library and that will provide us a bunch of queries for the dom and i will use get by text query we should check if we have this title in the dom so i will wrap it with expect function and i will run to be in the document function to check if this text exists in the document so we didn't import screen i will add it here and our tests are green again so this title exists and it's displayed in the document which is cool but i would like to check every post item so i would call forage iteration and check that every post title is displayed in the dom so instead of using this hard coded text i will use post title so we have a dynamic test right now let's continue with implementing other features for this post component first i will create a button so when user clicks on it it should open a form for creating a new post then i will create a form element and i will just put a header element inside so i want this form to be hidden by default and i will use use state react hook for that with state post form is visible and the default value will be false so form will be hidden by default and here is the conditional rendering part and when user clicks on it on this button i will call setpostform is visible and i will set it to true okay we pass a function on click wrongly so i will check it again yeah a callback function should be created this way and now it works so when i click on this button new post header will be visible i would like to hide this button when the form is visible and i will also add a cancel button inside the form so i can actually hide the form again and display add new post button so when user clicks on this cancel button i will set post form is visible to [Music] false so now we can toggle between showing and hiding the form i will continue with adding some input fields so the first field will be for new posts title and it will have type text of course with a placeholder attribute title and i will add a break element just to make it make a new line and after that i will add text area for new posts body with a placeholder body another break element and after that i will add button with type submit and i will also add a type button to the cancel button because i want to make a difference everything looks good and now i would like to handle form submit event so when user clicks on submit button i will actually call the server with post request and the method name will be handle on submit and i will create it right above return value so handle on submit will will have event as a parameter and the first thing that i'm going to do is to prevent default behavior i'm going to use fetch method with exactly the same endpoint but in this case i will use a post request so i will provide additional object with property method which will be set to post and in the body i will actually add a new post data for now i will set it to empty object and in order to create new post data i will create a new component state it will be named new post and set new post use date will have default value with title of empty string and the body of empty string so now the value will be equal to new post title property and in case of text area it will be equal to new posts body now when we open the form we have an error and that means that we will need to add on change event and reset the state when user change the input field value i will create a function with event property and i will set new post to the new value i will use spread operator of existing new and i will provide a new value for title from events target value basically i will keep the body value and add a new title value and i will do the same for the body text area i will just change title to body and i will use the same event target's value which comes from the input field and now when i type values for input and text area i should actually be able to use this state and before i do anything i will just console this date to make sure that everything works fine so now when i click on submit i have new post value in the browser's console so now we are ready to send this data to the server and i will provide it in a bot in the body property but before that i will use json stringify in order to parse that data correctly so inside json stringify i will just place new post state now let's check in the browser if everything works okay when i type new values and when i click on submit let's check network requests so we have a request payload but response is just an id and i would need to change actually content type that we are going to send to the server so inside headers i will add content type property and i will set the value to application slash json now when i click on submit the request payload is here and we have the correct response it works fine the response should be the newly created post and i would like actually to add it at the end of the existing list so when user clicks on submit the new post should appear at the end of the list in order to achieve that i will use then method which will parse response as json and another then method that will actually have data of the new post and now i will call setposts method and i will create a new array and i will use spread operator to use the existing posts and i will add the data at the end of this array now when i click on submit button i should see the new post at the end of the list for better user experience i would also like to hide the form when user submits the form and get successful response from the server so i will just call setpost form is visible and i will pass a false value as a parameter and i would also like to reset form input fields to empty string values i will call set new post and i will reuse this default data but first i will store it in a variable since i'm going to reuse it on few places i will name this variable new post default values now when i type values for new post and when i click submit the new post will be added at the end of the list and when i open the form again input fields will be empty and ready for creating another post but when i type something and when i click on cancel button after opening the form again the values of the input fields remain the same so i would like to reset the input fields when the user clicks on cancel button i will just create handle on cancel method and it will be a function that will call setpostform is visible and it will set it to false and i will provide handle on cancel for onclick event and it will also set new post to default values so right now when i click on cancel the input fields will be empty now that we are finished with implementing these functionalities we will continue with writing some tests i would like to test that clicking on cancel button will hide the form first thing that i want to do is to render post component but before that i would like to show you another way of handling asynchronous code from within testing environment and that would be by using wait for which is provided by testing library and you can wrap your code with wait for and with a weight in front of it and it will work so i will render posts component and the next line would be weight 4 because we have some asynchronous update of component state and inside the callback function i will use fire event from react testing library which will provide us different methods for simulating various events like clicking changing and all the stuff i will use click method and as a parameter we need to provide an element on which we would like to trigger click event that element will be add new pause button because we need to open the form before cancel it i will use screen api which is provided by testing library react so we can query our dom elements and find the add new post button i will use get by text query which will find the element with this text add new post now that we triggered click event on add new post button we are going to trigger another click invent for cancel button cancel button should be visible after clicking on add new post button so i will use the same query get by text but in this case text will be cancel before clicking cancel i will be able to find input elements and i will write expect assertion and i will search for element by placeholder text and in this case it would be title so i will select this input field and i will expect to have this element in the document when we click on add new posts that means that the form will be opened and in case of clicking on cancel button i would expect not to have this element in the document i will just add async in front of the function and i will replace get by placeholder with query by placeholder text we should use get by query when we expect to have this element in the dom and query by query will be used when we uh expect not to have the element in the dom i will just put not in front of to be in the document i would also like to test that clicking on cancel will reset the input fields so i'm going to check the value of the input field when user clicks cancel but before that i would like to trigger another event and that event will be change so i will write fire event change and i will provide query for input title and another parameter will be the value that i would like to change the input to so it will basically simulate typing by the user and it will change the value of the input field i would like to open the form again and i will trigger a click event on add new post button again after clicking on this button i would expect to have the value of the input field empty i would expect to be empty string let's see if tests are successful yeah everything is green and for practicing purpose we can also check the value of the input field after triggering change event the next test that i'm going to write is to check if the user is able to create a new post and we will also check submitting the form and we can also check rendering a new post i will create a function and first thing that i'm going to do is to render the posts component and i will put async because we will have ajax call to the server and therefore i will use wait for i will fire click event on add new post button and i will find it by query get by text so let's check tests everything is green and this part will be responsible for opening the form and after clicking on this button i would expect to have the input title with empty value i will do the same for text area for new posts body the tests are green so we will continue and i would also expect to have submit button visible on the screen so i will use get by role query and i will add additional parameter which is submit name which is like a text of this element all tests are green and the next phase would be to start typing but before this i would actually like to create some variables because i'm going to reuse the elements that i i selected i will store this title input in the variable and also body text area so i can reuse it later and i will now replace it i would like to trigger change event on title input i can actually reuse this variable now i would set target value to new post title and i will do the same for body input element but i'm just going to change the value to the new to new post body now i would like to trigger click event on submit button and i will call fire event click and i will actually create another variable to store this submit button so i can also reuse it and i will pass submit button element here and here for click invent and now uh we should actually add a weight and wait four because after clicking on submit button we are going to uh trigger fetch method which is asynchronous method so now it should work fine yeah and now we should check that the form is hidden after submitting the form i would expect that both input and text area elements do not exist in the dom so everything is green and now i would like to test that the new post that we submitted with the form will be displayed on the screen so we should actually check is there any element with the new post title text and the part where we add a new post to the list is here so basically we use response data from the server and we add it to the existing list in order to achieve this in the test we need to adapt the fetch mock a little bit we should actually check what is the provided method when we call fetch so in case it is a fetch with a post request we should return the newly created post and if it is a get method we should actually return the list of posts we will have two properties url and options and in case that we use fetch method for different urls we might want to use a switch case for urls but since we use only one url it is fine just to check the method so i will check if this request is the post method and if it's not i will just return promise resolve with mock posts data so i will assume that this is the get method and for the post method i would also return promise resolve but i'm going to create another mock post data and that will be single post i will just copy an item from this endpoint and now in case of post request i will return this mock so when user submits the form it should get this newly created post and i will actually use that data to trigger typing actually changing the input value and now i can actually search for the post that is added to the existing list of posts i will search for text and i will use this title from mock new post data and i would expect to be in the document and i can also search for body and since we have a line break in the body text we should actually search for the part of the body which make it easier so i will use regex and search for element that contains this part of the text and let's check tests so we have some errors and the error is cannot read property method of undefined okay so when we use fetch method for get request we actually don't provide method as a parameter because it has a default value so i will just add a question mark that means that the value of the options can be can be undefined and everything is green again simplicity reasons i used only one component posts but i would like to show you uh how you can test that some property functions are called from the single component so i will just create a new component for add new post button and first thing that i'm going to do is to import react and i will copy the template of the component and i will create a component function that should return this button and it should have a on click method as a property that should be passed from the parent component and i will also export this function as a default and now i will just use it instead of this button i would also need to provide onclick property so it should work the same and i will create test file for this component but we had an error i will check what it is uh okay so we need to import this component i will just import add new post button from this file and it should be fine okay we also need to add some tests to this file and it should work i will create describe function and inside i will create the first test and i will i would like to test that on click is triggered when user actually clicks on the button element first thing that i'm going to do is to render the add new post button component and i will pass a property on click and before that i will just create a on click mock function with just fn and i will pass this mock function as a onclick property so now i'm going to trigger a click event on this button so i will import screen and i will use get by query to find the button and it has add new post text so now i would expect that this on click callback function would be called and i will use to have been called method and let's check tests it fails okay we uh we should import render from testing library uh that is the issue so now it works fine yeah everything works fine so we can also use similar approach to test that fetch method is being called when the component is mounted so i will write expect window dot fetch and i will call to helping called with because i want to check that this fetch method is called with the parameter which is the endpoint from jsonplaceholder and here it is so i would like to test that the fetch method is triggered with this endpoint and the tests are green
Info
Channel: codepanion
Views: 3,319
Rating: 5 out of 5
Keywords: react, jest, testing library, web, javascript, test, unit tests, integration tests, tutorial, react.js
Id: Jew6yQUHSPI
Channel Id: undefined
Length: 44min 1sec (2641 seconds)
Published: Thu Jan 28 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.