We always want to build great user interfaces. Usually, we spend most of our time on improving styles and the user experience. We write and change a lot of UI-related code. So, it’s very important to use proper testing methods for the UI code.
In this article, I’ll talk about how we can test React UI components. First, I’ll discuss some concepts, then I will show you how to implement those concepts with the correct tools.
UI testing is always hard. There are some things you can automate. And there are some things you need to test manually. We try to minimize the manual testing. But when we want to create a great user experience, manual testing is really important.
I’d like to divide UI testing into two categories:
Here we test the functionality of our components. For example, let’s say we’ve a button component. It should trigger an event if someone clicks on the button.
With functional testing, we test scenarios like that. If our button component doesn’t trigger the event, that’s a test failure.
Visual testing is something that has to be done with human eyes. For example, say we need to
These things are pretty hard (or impossible) to automate as they involve our taste and human thinking.
Both types of test are equally important. If a function or a visual test fails, your whole test should fail. That means, there’s an issue somewhere in your app.
Assume our app is an e-commerce product. Let me show you some examples:
Let’s say the click event of a button in your app is not working. Then it’s a total failure and users might not be able to order products.
Assume one of your designers has changed the background color for a seasonal offer. Unfortunately now, the background color is the same as the button text color. So, your users can’t locate the order button.
As you can see, a tiny change could destroy your whole app. The failure could be from a functional test or a visual test. So, both types of tests are just as important.
:sunglasses: : Okay. I got it. Show me how to write these test cases.
Fortunately, React has an amazing set of tools to write these kinds of tests. Let’s have a look at them.
For testing React components, we’ll use enzyme . It’s simple and has many features.
Shallow rendering is very interesting. Only the first level of components is rendered inside your component. The test runner doesn’t need to worry about DOM and the execution environment, which is great for functional testing.
Let’s write a simple test case. Say we are trying to check a button’s onClick event handler. Here’s the code:
Sometimes, you need to test your components with a full DOM environment. This is important if your components change the DOM directly, utilize browser features or use React’s life cycle hooks (like the componentDidMount hook).
Other than that, you need to run your tests inside a DOM environment. For that, you have a few options:
:sunglasses: : Wow! This looks like fun. So, how we are going to do the visual testing?
We do visual testing with our naked eyes. For the things we can’t automate, we use visual testing.
For that, we have a great tool. It’s React Storybook , which we use to create stories for different scenarios and then test them. A story is a single use case of your component. It’s like a unit test, but a visual test.
Once configured, this is how we can write some stories for our button component:
Then, you can visually inspect these stories via the storybook console:
So, you can identify if there are any visual issues.
There are different ways to write these visual and functional tests depending on the situation.
Initially, we write stories with React Storybook . Its hot reload functionality is great when we are designing and developing the initial version.
Then, once we have a good design, we write our functional tests.
Initially, we usually don’t try to create visually great UIs. We are only looking to build something functional.
After the initial design, we improve our UIs to create a great user experience.
These design changes may break the functionality. We can check that using the functional tests. So, after a design change, we run the functional tests and see whether the change has broken the functionality.
We can use a utility to run the tests as we edit the code, giving us real-time feedback.