How to Test With Jest
Hi there, welcome back! Thank you for stopping by. Last month in my Getting Started with AWS article I wrote:
“ If you are a budding developer looking to get that first opportunity, it is important to get familiar with some of the different cloud infrastructure providers out there. ”
The exact same can be said for writing tests for your code and the Testing Frameworks and libraries that help you do it. In this article, we will walk through setting up some unit tests with
react-testing-library for some components in an existing React application.
What is Jest?
What is React Testing Library?
React Testing Libraryis a very light-weight solution for testing React components. It provides light utility functions on top of
react-dom/test-utils, in a way that encourages better testing practices. Its primary guiding principle is:
So rather than dealing with instances of rendered React components, your tests will work with actual DOM nodes. The utilities this library provides facilitate querying the DOM in the same way the user would.
Let’s get started!
For this example, we have a simple SPA bootstrapped using the
create-react-app your-apps-name command. The app has 2 simple components, a counter with “up” and “down” buttons. Clicking them increases and decreases the count displayed on the screen. The other component is a basic form with a submit button. Filling the form and clicking submit will display the message typed in the form.
When you create projects using the
Create React App command, you have out of the box support for React Testing Library and Jest. If you didn’t use that command, you can add them via
npm like so:
// Install React Testing Library
npm install --save-dev @testing-library/react// Install Jest
npm install --save -dev jest
As mentioned, our first component is the
As you can see, it is a very simple component that manages state locally with the
useState hook(line 5 and 6). It has a single arrow function called
handleClick (line 8) that manages both button clicks with some conditional statements. It also removes the element from the screen based on a nested conditional statements(line 17).
Our second component is the
This component has a bit more going on. Again, we manage all our state attributes with the
useState hook(lines 4 – 7). In this case, we have a
handleChange arrow function (line 9) that manages input changes on the form when the user is typing in the input field. Finally, we have a
handleClick arrow function (line 13) that triggers all our state changes. Also, this component disables the “Print” button if there is no data in the input field.
The App Test
Since our app was bootstrapped with
create-react-app there is already one test file available for us in the
src directory of the app called
App.test.js. Let’s break this down a bit.
This is the test file for the
App.js component. Notice that like any other React component it starts by importing React (line 1). Then we import the necessary functions from React Testing Library(line 2) followed by importing the component to be tested(line 3).
As the test indicates it is expecting that our App component “renders learn react link” (line 5). To verify this we need to destructure the
getByText query and make it equal to the
render function we imported and we pass it our component(line 6). This basically tells our query where it is going to be looking. Then we create a variable and assign it the return value of the
getByText query and pass in the text we are looking for. In the example above, line 7 is passing in a regular expression of the desired text. Now that the query is ready to go the expectation can be set. Here, we expect the text “learn react” to be in the document. This is the basic structure of the tests we will be writing.
// To run tests use these commands// If using yarn
yarn test// If using npm
Currently, this test is failing because we changed all the code this was testing for. If you are following along, you should see something like this.
Let’s update our test so we are looking for stuff that actually exists in our document.
Ok, above we have the same test but we added some new variables with a few examples of different ways we are able to search for text. Line 11 shows an example that searches for a string and uses a flag to ignore case sensitivity. Lines 14 and 15 show 2 ways of using regular expressions. Line 15 is looking for a full string match while ignoring case and line 14 is looking for substrings while ignoring case. Now, when we run our test it passes.
The Counter Test
Let’s break down the steps to writing your test from scratch.
1 - Create a test file
Create a new file in the
src directory with the name of the component to be tested. All test files should follow the same naming convention
ComponentName.test.js. In our case, we are testing the
Counter component so our file will be called
2 - Import React, components, and functions
As we did before we go through our imports and this time we also include the
FireEvent function from React Testing Library. This will allow us to simulate button clicks in our tests.
3 - Write functionality tests
With everything in place, we can start writing our test. Since we are already checking that our components render correctly in our
App.test.js file, we can test the functionality of the buttons by testing their individual actions and results.
Testing the “Up” button
In this test, we are making sure that when we click the “Up” button for the first time we get the number 1 printed on the screen. To achieve this, we will be looking at multiple values.
- The text on the button.
- The text we are looking for as a result of clicking the button.
This means we will need to use a different query function other than
getByText. Thankfully, there is a very flexible one called
getByTestIdthat allows us to search by an id we create on the component we are testing using the
Then in our test, we can access that id like this.
On line 14 we destructure our
getByTestId query and pass it as an argument to our
fireEvent.click() function and include the
testId we created.
With that test passing, we can pretty much do the same for the “Down” button.
In order to be able to test that the “Down” button decrements the count correctly we have to increment the count first so we added an extra click event on line 26 then we check that the number incremented and then we fire the down click event on line 34.
The Printer Test
Printer component has a text input and a submit button. We are going to test a few things here.
1 - Repeat steps 1 and 2 from the previous test.
2 - Start writing tests
In this example, want to make sure the input field renders. We also so want to test if the input field updates when the user types into it.
We will start with a new describe block.
We’ll group all our input tests inside this block. Our first test will check that the input field renders correctly.
React Testing Library has many queries at our disposal. Here is a very handy cheatsheet. Since we are looking for the text in the component and our component is just the input and buttons we can use the
getByPlaceholderText query. Note that this is not the best practice. Normally, we would be using form tags and there would be labels for each input of the form, etc.
So far all our tests should be passing.
Now we can move on to testing if it updates on change.
As you can see on line 29, we are using a different event called “change”. This allows us to simulate a user inputting text into a form or input field.
Now our describe block should look like this.
And all our tests are passing.
Now we want to make sure that our
Then we want to add another test inside this describe block to make sure our “Print” button is not disabled when there is data in the input field.
Our “print button” describe block should now look like this. I will remove the notes just so it all fits in the image.
Now, we can add our second case inside its own describe block. Here we want to check that the button is disabled when there is no data in the input field.
This is what our finished “print button” block should look like.
And our tests are all passing!
Just like that, we have written 3 test suites with a total of 8 tests for App and our 2 components. Here is the working app.
I hope this was fun and informative. I’d love to hear your thoughts in the comments. As always, stay healthy, stay curious!