How to get started testing React applications
All of this testing thing is like I'm in a maze!
If you don't have experience writing tests, getting started can be daunting. Especially if you're trying to test code that interacts with a framework/library like it is when you're testing a React application.
In this article, we'll go over the usual tools to test a React application, how to get unstuck when we don't know how to test a piece of code, and also a basic testing methodology that allows us to get started right away. In the end, there will be an exercise to put into practice what we've covered.
Learning how to write tests is a long process. Don't be discouraged!
Keep in mind that learning how to write tests effectively has a steep learning curve. You'll have doubts about what to test. You won't know how to test some piece of code. You'll under-test. You'll over-test. You'll feel slowed down by testing and start wondering why to do it at all, and eventually, you'll reach a point where you're comfortable writing automated tests and understand the tradeoffs you're making with each test you write.
The struggle is normal, and it's part of the journey, don't be discouraged by it. Keep testing, and it will get better.
Jest is a testing framework that allows you to run your automated tests and also provides you with functions to make assertions, such as "did this function returned the expected value?" or "has this function thrown the expected exception?".
Testing React components has some peculiarities. So the community uses React Testing Library, which is a library that provides utility functions to make testing React components easier.
Cypress is a tool that's normally used to run E2E tests. If you're starting, don't worry too much about learning this tool. You'll be using it the least, and if you feel comfortable using Jest and React Testing Library, it'll be easier to get the hang of Cypress.
To avoid complications setting up a testing environment with Jest, while still getting familiar with the tools, I suggest starting a project with Create React App. It already has Jest configured, and also has excellent documentation on how to run and debug tests.
One of the challenges with testing is knowing how to test a particular use-case. Use-cases can be general like data-fetching or triggering events, or more particular like how to test a piece of code that uses React Router. The strategies to handle those use-cases we call testing recipes or testing patterns.
You don't need to know all recipes before starting to write tests. What's important is that you know that the concept of recipes exist and you know where to look for them when you need them.
The best place to find testing recipes is usually the documentation of the tools you're using to write tests and the documentation of the libraries you're using to write your production code.
Testing some code that uses React Router? Check their documentation on testing. Using React Testing Library? Check their guides and recipes. Using React? React also has documentation on testing. And the same goes for Jest.
When you don't know how to test a piece of code or want to find a better way to test it, check the documentation of the tools you're using.
Recipes tell you how to test something, but they won't tell you what to test and how to incorporate testing in your development process. That's where a methodology comes in.
Some of the important things about a testing methodology are:
- Give you confidence that the code you wrote works.
- Allow you to refactor code without fear of breaking what's working.
- It makes you more productive on the medium to long term.
Effectively using a testing methodology is the hardest of writing automated. Most of your frustrations and doubts will come from here.
My suggestion when starting is to keep it as simple as possible, so you can start writing tests right away. Usually, the more natural approach is to program a feature or a sub-feature and then write tests for it, so I recommend you start there. You may need to change the code you've written to write tests for it, and that's fine.
If you're not sure what constitutes a feature, think of it as a set of behaviors your user cares about. Are you making an app that lets your user search for movies? Then it's a good idea to have a set of tests that checks the user can search for a movie and see the results of that search, as well as what happens when you don't find any movies or if there was an error.
I use Test-Driven-Development(TDD), so my testing methodology is embedded in this broader development process. Although some people can take it way too far and turn it into a religion, I recommend you try it out with a pragmatic mindset. It helps me know what to test and stay focused on my work. If you're curious about learning TDD, I recommend you read the book Test Driven Development: By example by Kent Beck.
Exercise: Get comfortable with testing tools and documentation
The goal of this exercise is to get you familiar with the tools you'll be using for testing, and also to create the habit of checking documentation for testing recipes. Keep in mind that the tests you'll be writing in this exercise aren't necessarily the tests you'd be writing in a professional application.
Even if not everything on those two pages seems useful, finish reading them. It will help breed familiarity with the tools and make them easier to use.
2. Create a React application using Create React App
This application is where you'll be writing your tests.
3. Write a test for an add function
Write a simple add function and then write a test to assert that 6 + 4 = 10. If you're not sure how to assert two values are equal, check Jest's documentation. Now that you've written a test, run it. If you read Create React App documentation on running tests, you should know how to do it.
4. Read React Testing Library Introduction and Example
Reading React Testing Library documentation will give you familiarity with the tool principles and API and thus make you use it better. Yet again, don't worry if not everything makes sense from the start.
Notice that the version of React Testing Library that comes by default with the Create React App may not be the most up to date, so the methods shown in the documentation may not be available to you. To update to the current version of React Testing Library, you'll need to reinstall it. You may also need to update the jsdom version Jest is using. To do that, install the most up to date package of the jsdom environment for Jest, as of now jest-environment-jsdom-sixteen, and change the testing script to use the new environment. It should look something like this:
"test": "react-scripts test --env=jest-environment-jsdom-sixteen"
5. Write tests for a React component that adds two numbers
Make a simple React component that allows a user to add two numbers and see the result. Use the add function from before. Keep the UI simple. Two labeled inputs for the numbers, a button to make the addition, and a place to see the result.
Now write a simple test using React Testing Library to assert that the two inputs and the button to perform the addition are rendered. If you've read Jest's documentation on running tests, you've already seen a piece of code that uses what you need for this.
Now write a test that asserts 3 + 4 = 7. For this, you'll need to simulate a user entering numbers and clicking on the button to perform the addition. If you've read Rect Testing Library example, you already know what module from React Testing Library you'll have to use to simulate a user changing an input and clicking on a button. If you're still lost, use the search bar on React Testing Library documentation to look for docs about what you're trying to test.
6. Make your add function async and adapt your code and tests to the change
Make your add function return a
Promise of a number instead of a number. The
Promise should resolve after 500ms. Also, adapt the React component to work with the now asynchronous add function.
You now have to change the tests for the add function and the React component, since now they're failing.
For the add function, you'll have to change your test to assert the result of a
Promise. You may not be sure how to test a function that returns a promise, in which case check the documentation.
For the React component, you'll have to deal with the fact that the result of the addition won't be there right after the user clicks the button. A simple approach to this problem is to wait for the result to appear on the screen. By now, you probably already know where to look for that. But in case you're in doubt, here's the react testing library documentation.
If you've managed to get to the end of this exercise congratulations! You now have some familiarity with the tools involved in the day to day testing of a React application, as well as some experience with testing asynchronous code.
If doing this exercise felt hard and not that straightforward, don't worry. Struggling with the tools and exploring documentation is part of the learning process. Next time it will be easier.
In case you want to check what a solution to this exercise, you can check this gist.
Keep in mind that learning how to write tests effectively has a steep learning curve. Don't be discouraged if it feels like it's hard work.
To effectively write tests, you'll need to know some tools, know where you can find testing recipes, and have a testing methodology established.
If you're struggling with testing a piece of code, look for a solution on the documentation of tools and libraries you're using.
Start with the simple testing methodology of writing automated tests after writing the code for a feature. Test the behavior the user cares about and test enough to make yourself comfortable that the code works. If you want to check other testing methodology, consider reading Test Driven Development: By example
Do the exercise shown in this article so that you get comfortable with testing tools and documentation.
And last but not least, keep writing tests and evaluate the value they're bringing to you and the project. If you do this, the quality of your tests and code will keep improving.
One of the challenges of writing automated tests is knowing what to test. And great way to deal with this problem is to learn how to make a test list out of feature requirements.
So if you're looking to improve your testing skills, learning how to make a test list is a great next step to take.