The Basics of React Unit Testing

Inigo Ramli
6 min readMar 22, 2021

Unit testing has been an integral part of the Agile methodology. It is the core part of Test Driven Development paradigm. This paradigm asserts that all implementations of a project are ought to be accompanied with test codes designed to check the outcome of each unit code. Nowadays, almost every mainstream programming language has at least one test suite available. Django and Flask each have their own testing suites. Java has JUnit. C++ have various test suites available for their own specific use case.

For me at least, unit testing has been associated with backend programs: Codes that are built for computing purposes and (usually) consists of procedures that can be divided into several core parts. These core parts are then tested using unit testing. I have never heard about unit testing on frontend programs though. Even during my internship a year back using React, I did not encounter any kind of unit testing for JavaScript. So, it is quite interesting for me when I found out that there is a testing suite for React framework during my work at TBCare web application.

At the start, I can see why this makes sense: React has been marketed as being close to Object Oriented. React allows the developer to create reusable components and attaching attribute and functions known as props to each component. This means that there are procedures to be tested.

So, I would like to explain on what I learned about unit testing in React based on my work at TBCare web application: The libraries used, and it’s analogy to the testing suites in programming languages that I am more familiar with, such as Python and Java.

Jasmine: The foundation of JavaScript Unit Testing

Let’s start with the most basic function of unit testing: Assertions. In general, you will need a framework that can tests whether a condition is true (or false). In Django, this is done using the assert functions on Django UnitTest class. Similiarly, JavaScript has a framework called Jasmine. Taken from the description in it’s documentation webpage: “Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.”. Here you can see that Jasmine can be used regardless of what main framework you are working on.

Testing in Jasmine is structured on a set of describe() functions. Each describe() function may contain several it() functions. This is roughly equivalent to how unit testing in JUnit and Django is organized. On both framework, tests are created inside a method, which is created inside a class. Normally, each test class is delegated for exactly one object, and each test method is coded to test exactly one scenario on that object. In Jasmine, each describe() function covers one object, and each it() function covers for one scenario on that object.

After knowing how test functions are structured, we need an assertion function. Jasmine provides us with the expect() method for this purpose. There are various functions derived from expect(), but generally they are designed to be as human readable as possible.

For example, here is a very simple test that performs one assertion:

var a = true;describe("Object a", function(){
it("Should have the value true", function(){
expect(a).toBe(true);
})
})

The meaning of this code snippet should hopefully be obvious. It tests whether variable ‘a’ is true.

Testing React Components with Enzyme

So far we have learned on how to perform assertions in JavaScript. Now, it is time to take the object meant to be tested to the testing realm, in this case Jasmine. Jasmine as a testing framework works well on primitive objects, but it may not be adequate to test more complex functions. Mainstream frameworks usually make another framework-specific suite built to test a more framework-specific usage. Django for example, embeds a Client object in their TestCase suite to simulate API calls. In the context of React, we want to render components, check their prop values, and perform some user interaction (e.g. clicking a button) to the rendered objects. To do this, React provided a tool called Enzyme. Enzyme allows us to render React components and check it’s behavior and values using separate tools of our choice.

There are at least two ways provided by Enzyme to render a component: shallow() and mount(). On most cases, you should start with shallow() to perform rendering. mount() can be used if a test in componentDidMount() function is needed.

Below is an example on how shallow() is used in TBCare:

import React from 'react';
import { shallow } from 'enzyme';
import Home from '.';

it('render Home component without crashing', () => {
home = shallow(<Home />);
});

The shallow() function renders the Home component, allowing it to be referenced in further assertions. For example, this line below

expect(home.prop('color')).toBe('Green');

Will perform a comparison between attribute ‘color’ of the rendered object ‘home’ and check if it equals ‘Green’.

One can also simulate a user interaction. Suppose that the Home component has a button named ‘btn’, then this line:

home.find('btn').simulate('click');

Should simulate a button click. If ‘btn’ has an onClick() method attached, it will be called and it’s effect can be observed using Jasmine as well.

Jest for Mocking Objects

There is one more important component in a good test suite: Mocks. It is rare for a function in a large project to be independent. Most of the time, a function depends on another service or component. Take for example, a function that performs a connection with outside API. Creating a test that depends on this API being active is generally not a good idea. The same goes for objects that depends on an external database, or perhaps another component that needs to be instantiated with numerous other objects. Tests are supposed to be independent from other components, so to avoid working with these other dependencies, a mock object is used.

Mock object is best described as a dummy. It is designed to behave just like it’s real counterpart, but not necessarily invokes the same functions or procedures. They are declared before a test is started and can be used and disposed with minimal side effect to the real world.

If JUnit solved this issue with mockito and Python with MagicMock, then JavaScript has Jest: A tool that can mock functions and track them for testing.

Below is an example:

import dog from 'dog';function cat(){
var ten = dog(); // We don't want to call this
return ten + 5;
}

We wish to test the value of the cat() function without invoking the dog() function for one reason or the other (Let’s just say that both of them just cannot work together without some complicated initialization!).

Here is one way to mock and test the function using Jest:

import dog from 'dog';
import cat from 'cat';
it('should add 5 to whatever dog is returning', function(){
jest.mock(dog);
dog.get.mockResolvedValue(10); // MAke dog return 10 when called
expect(cat()).toBe(15);
})

Conclusion

It was a surprising news for me when I found out that JavaScript has a sophisticated test suite that van be used to test the behavior of React components. After working with the first sprint in TBCare development, I have learned at least three tools for testing React programs: assertion, rendering, and mocking. These three components combined can be used to test most use cases and further integrating the TDD paradigm into front end development.

--

--

Inigo Ramli

Computer Science student at Universitas Indonesia. An avid competitive programmer and participated in ICPC