In this tutorial, we are going to do react unit testing for a basic to-do application using Jest testing and Enzyme testing.
Jest Testing
The Jest is a JavaScript testing framework designed to ensure the correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar, and feature-rich API that gives you results quickly. We are going to jest unit testing here.
Jest is well-documented, requires little configuration, and can be extended to match your requirements. For more information on Jest check out its official documentation. https://jestjs.io/docs/en/getting-started
Enzyme Testing
The Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components’ output. You can also manipulate, traverse, and in some ways simulate runtime given the output. For more information check out Enzyme’s official documentation.
https://enzymejs.github.io/enzyme/
Looking for React Dashboards?
- Try our React Dashboard and create stunning web applications for unlimited client projects and personal projects.
- Start building web applications and products using our Free React Templates without any investment.
Setup
In this tutorial for react unit testing, we will make use of the create-react-app CLI tool to setting up our project and do react unit testing. So go to a directory where you will store this project and type the following in the terminal
create-react-app note-redux-app
If you don’t have create-react-app installed type the following command in the terminal to install it globally.
npm install -g create-react-app
Install Enzyme
npm install --save-dev enzyme enzyme-adapter-react-16 enzyme-to-json
The Jest unit testing framework is by default bundled into create-react-app.
In the src folder, create a tempPolyfills.js file with the following content. This is necessary for testing older browsers.
const raf = global.requestAnimationFrame = (cb) => {
setTimeout(cb, 0);
};
export default raf;
In the src folder, create a setupTests.js file with the following content
import raf from './tempPolyfills'
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
For the styling of our todo application, we will make use of the semantic UI library. In the index.html file of our project, we will add the semantic UI library using the CDN link.
In the app.js file, add the following code snippet
import React from 'react';
class App extends React.Component {
render() {
return(
<div
className='ui text container'
id='app'
>
<table className='ui selectable structured large table'>
<thead>
<tr>
<th>Items</th>
</tr>
</thead>
<tbody>
items
</tbody>
<tfoot>
<tr>
<th>
<form
className='ui form'
>
<div className='field'>
<input
className='prompt'
type='text'
placeholder='Add item...'
/>
</div>
<button
className='ui button'
type='submit'
>
Add item
</button>
</form>
</th>
</tr>
</tfoot>
</table>
</div>
)
}
}
export default App;
With this, we can view the static version of our to-do app.

Let’s make our todo app reactive with the following code snippet
First, our todo app needs a state to store the todo items and a todo item.
The following piece of code should be added to app.js
state = {
items: [],
item: '',
};
Next, we will bind the input to the item property of our state. Hence the input tag in app.js should be updated as follows
<input
className='prompt'
type='text'
placeholder='Add item...'
value={this.state.item}
onChange={this.onItemChange}
/>
Since the onChange event is bound to the onItemChange method, in order to update the item property in our state with the value of the input field. The onItemChange method should be as the following:
onItemChange = (e) => {
this.setState({
item: e.target.value,
});
};
Submitting the Form
If the input field is empty the submit button is disabled. For this feature, add the code snippet below immediately after the render method
const submitDisabled = !this.state.item;
Our add item button should be updated as the following
<button
className='ui button'
type='submit'
disabled={submitDisabled}
>
To submit our to-do item, we will add an onSubmit event listener to our form which will trigger the execution of the addItem function.
an onsubmit event should be added to the form tag as the following
onSubmit={this.addItem}
The addItem function should be as the following
addItem = (e) => {
e.preventDefault();
this.setState({
items: this.state.items.concat(
this.state.item
),
item: '',
});
};
Listing all To-Do Items
To list all the to-do items we need to iterate over each to-do item in the items array.
<tbody>
{
this.state.items.map((item, idx) => (
<tr
key={idx}
>
<td>{item}</td>
</tr>
))
}
</tbody>
Finally, our todo app should be as the following code snippet.
import React from 'react';
class App extends React.Component {
state = {
items: [],
item: '',
};
onItemChange = (e) => {
this.setState({
item: e.target.value,
});
};
addItem = (e) => {
e.preventDefault();
this.setState({
items: this.state.items.concat(
this.state.item
),
item: '',
});
};
render() {
const submitDisabled = !this.state.item;
return(
<div
className='ui text container'
id='app'
>
<table className='ui selectable structured large table'>
<thead>
<tr>
<th>Items</th>
</tr>
</thead>
<tbody>
{
this.state.items.map((item, idx) => (
<tr
key={idx}
>
<td>{item}</td>
</tr>
))
}
</tbody>
<tfoot>
<tr>
<th>
<form
className='ui form'
onSubmit={this.addItem}
>
<div className='field'>
<input
className='prompt'
type='text'
placeholder='Add item...'
value={this.state.item}
onChange={this.onItemChange}
/>
</div>
<button
className='ui button'
type='submit'
disabled={submitDisabled}
>
Add item
</button>
</form>
</th>
</tr>
</tfoot>
</table>
</div>
)
}
}
export default App;
Testing our To-Do App with Jest Unit Testing and Enzyme Test
create-react-app sets up a dummy test for us in the app.test.js file. Let’s execute the initial test for our project with the following command in our project folder.
npm test

Open up App.test.js and clear out the file. At the top of that file, we first import the React component that we want to test, import React from react, and shallow() from the enzyme. The shallow() function will be used to shallow render components during the test.
In our first test case, we will assert that our table should render with the header of items. In order to write this assertion, we’ll need to:
Shallow render of the component
Traverse the virtual DOM, picking out the first the element
Assert that the element encloses a text value of “Items”
import App from './App';
import React from 'react';
import { shallow } from 'enzyme';
describe('App', () => {
it('should have the `th` "Items"', () => {
const wrapper = shallow(
<App />
);
expect(
wrapper.contains(<th>Items</th>)
).toBe(true);
});
});
The shallow() function returns what Enzyme calls a “wrapper” object, Shallow Wrapper. This wrapper contains the shallow-rendered component. The wrapper object that Enzyme provides us with has loads of useful methods that we can use to write our assertions. In general, these helper methods help us traverse and select elements on the virtual DOM. One of the helper methods contains (). It is used to assert the presence of an element on the virtual DOM.
contains()accepts a React Element, in this case, JSX representing an HTML element. It returns a boolean, indicating whether or not the rendered component contains that HTML.
With our first Enzyme spec written, let’s verify everything works. SaveApp.test.js and run the test command from the console using the following command:
npm test
Next, let’s assert that the component contains a button element that says “Add item.”
Add the code snippet below after the previous ‘it’ block
it('should have a `button` element', () => {
const wrapper = shallow(
<App />
);
expect(
wrapper.containsMatchingElement(
<button>Add item</button>
)
).toBe(true);
});
Noticed something new? Instead of using the contains() Enzyme Wrapper method we just used the containsMatchingElement Enzyme Wrapper method. If we use contains, we need to pass contains() a ReactElement that has the exact same set of attributes. But usually, this is excessive. For this spec, it’s sufficient to just assert that the button is on the page. We can use Enzyme’s containsMatchingElement() method. This will check if anything in the component’s output looks like the expected element.
We don’t have to match attribute-for attribute using the containsMatchingElement() method.
Next, we’ll assert that the input field is present as well:
it('should have an `input` element', () => {
const wrapper = shallow(
<App />
);
expect(
wrapper.containsMatchingElement(
<input />
)
).toBe(true);
});
Next, we will assert that the button element is disabled
it('`button` should be disabled', () => {
const wrapper = shallow(
<App />
);
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
The find() method is another Enzyme Wrapper method. It expects an Enzyme selector as an argument. The selector in this case is a CSS selector, ‘button’. A CSS selector is just one supported type of Enzyme selector. For more info on Enzyme selectors, see the Enzyme docs. We used first to return the first matching element. To read the disabled attribute or any other attribute on the button, we use props(). props() returns an object that specifies either the attributes on an HTML element or the props set on a React component.
Using beforeEach
In all popular JavaScript test frameworks, there’s a function we can use to aid in test setup: beforeEach. beforeEach is a block of code that will run before each block. We can use this function to render our component before each spec.
At this point, our test suite has some repetitious code. In our previous assertions, we shallow rendered the component in each it block. To avoid these repetitions, we will refactor our assertion. We will just shallow render the component at the top of our describe block:
Our refactored test suit should look like the following
describe('App', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(
<App />
);
});
it('should have the `th` "Items"', () => {
expect(
wrapper.contains(<th>Items</th>)
).toBe(true);
});
it('should have a `button` element', () => {
expect(
wrapper.containsMatchingElement(
<button>Add item</button>
)
).toBe(true);
});
it('should have an `input` element', () => {
expect(
wrapper.containsMatchingElement(
<input />
)
).toBe(true);
});
it('`button` should be disabled', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
});
Testing for User Interactions
The first interaction the user can have with our app is filling out the input field for adding a new item. We will declare another describe block inside of our current one in order to group the test suits for the user interactions. describe blocks are how we“group” specs that all require the same context.
The beforeEach that we write for our inner description will be run after the before Each declared in the outer context. Therefore, the wrapper will already be shallowly rendered by the time this beforeEach runs. As expected, this beforeEach will only be run for its blocks inside our inner describe block
We will use the simulation method to simulate user interactions.
The simulation method accepts two arguments:
- The event to simulate (like’change’or’click’). This determines which event handler to use(like onChange or onClick).
- The event object (optional)
Notice that in our todo app, when the user has just populated the input field the button is no longer disabled.
So, we can now write specs related to the context where the user has just populated the input field. We’ll write two specs:
That the state property item was updated to match the input field
That the button is no longer disabled
describe('the user populates the input', () => {
const item = 'Laundry';
beforeEach(() => {
const input = wrapper.find('input').first();
input.simulate('change', {
target: { value: item }
})
});
it('should update the state property `item`', () => {
expect(
wrapper.state().item
).toEqual(item);
});
it('should enable `button`', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(false);
});
});
In the first spec, we used wrapper.state() to grab the state object. We use the state() method which retrieves the state property from the component.In the second, we used props()again to read the disabled attribute on the button.
After the user has filled in the input field, There are two actions the user can take from here that we can write specs for:
- The user clears the input field
- The user clicks the “Add item” button
Clearing the input field
When the user clears the input field, we expect the button to become disabled again. We will build on our existing context for the description “the user populates the input” by nesting our new description inside of it:
describe('and then clears the input', () => {
beforeEach(() => {
const input = wrapper.find('input').first();
input.simulate('change', {
target: { value: '' }
})
});
it('should disable `button`', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
});
We used beforeEach to simulate a change event again, this time setting the value to a blank string. We’ll write one assertion: that the button is disabled again.
Whenever the field is empty the button should be disabled.
Now, we can verify that all our tests pass.

Next, we’ll simulate the user submitting the form.
Simulating a form submission
After the user has submitted the form, We’ll assert that:
- The new item is in the state (items)
- The new item is inside the rendered table
- The input field is empty
- The “Add item” button is disabled
So we’ll write our describe block inside “the user populates the input” as a sibling to “and then clears the input”:
describe('and then submits the form', () => {
beforeEach(() => {
const form = wrapper.find('form').first();
form.simulate('submit', {
preventDefault: () => {},
});
});
it('should add the item to state', () => {
});
it('should render the item in the table', () => {
});
it('should clear the input field', () => {
});
it('should disable `button`', () => {
});
});
Our beforeEach will simulate a form submission. Recall that addItem expects an object that has a method preventDefault().
We’ll simulate an event type of submitting, passing in an object that has the shape that addItem expects. We will just set preventDefault to an empty function:
With our beforeEach() function in place, we first assert that the new item is in the state:
it('should add the item to state', () => {
expect(
wrapper.state().items
).toContain(item);
});
Jest comes with a few special matchers for working with arrays. We use the matcher toContain()to assert that the array items contain the item.
Next, let’s assert that the item is inside the table.
it('should render the item in the table', () => {
expect(
wrapper.containsMatchingElement(
<td>{item}</td>
)
).toBe(true);
});
Next, we’ll assert that the input field has been cleared.
it('should clear the input field', () => {
const input = wrapper.find('input').first();
expect(
input.props().value
).toEqual('');
});
We’ll assert that the button is again disabled:
it('should disable `button`', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
Finally, our app.test.js file should contain the following
import App from './App';
import React from 'react';
import { shallow } from 'enzyme';
describe('App', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(
<App />
);
});
it('should have the `th` "Items"', () => {
expect(
wrapper.contains(<th>Items</th>)
).toBe(true);
});
it('should have a `button` element', () => {
expect(
wrapper.containsMatchingElement(
<button>Add item</button>
)
).toBe(true);
});
it('should have an `input` element', () => {
expect(
wrapper.containsMatchingElement(
<input />
)
).toBe(true);
});
it('`button` should be disabled', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
describe('the user populates the input', () => {
const item = 'Vancouver';
beforeEach(() => {
const input = wrapper.find('input').first();
input.simulate('change', {
target: { value: item }
});
});
it('should update the state property `item`', () => {
expect(
wrapper.state().item
).toEqual(item);
});
it('should enable `button`', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(false);
});
describe('and then clears the input', () => {
beforeEach(() => {
const input = wrapper.find('input').first();
input.simulate('change', {
target: { value: '' }
})
});
it('should disable `button`', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
});
describe('and then submits the form', () => {
beforeEach(() => {
const form = wrapper.find('form').first();
form.simulate('submit', {
preventDefault: () => {},
});
});
it('should add the item to state', () => {
expect(
wrapper.state().items
).toContain(item);
});
it('should render the item in the table', () => {
expect(
wrapper.containsMatchingElement(
<td>{item}</td>
)
).toBe(true);
});
it('should clear the input field', () => {
const input = wrapper.find('input').first();
expect(
input.props().value
).toEqual('');
});
it('should disable `button`', () => {
const button = wrapper.find('button').first();
expect(
button.props().disabled
).toBe(true);
});
});
});
});
Now, we can verify that all our tests pass. React Unit Testing
If you are looking for a React MUI Admin Dashboard Template then you can check out below useful Admin Template which can save you time, money, and energy:
Modernize Free React MUI Dashboard

Conclusion
I hope you have now a good idea about how react unit testing is done. In total, so far we’ve learned how to organize our test code in a behavioral-driven manner, shallow rendering with Enzyme. How to use the shallow Wrapper methods for traversing the virtual DOM, how to use Jest matchers for writing different kinds of assertions (like toContain() for arrays). Finally, we saw how we can use a behavioral-driven approach to drive the composition of a test suite in react using the Jest unit test and Enzyme test frameworks.
Related Article: Top 42 React resources every developer should bookmark [Latest]
What’s up Dear, are you genuinely visiting this web site regularly,
if so after that you will definitely take nice experience.
Usually I do not learn article on blogs, but I wish to say that this write-up very compelled me to take a look at and do
so! Your writing taste has been surprised me.
Thanks, very nice article.