Unit Testing React Component with Jest and Enzyme (Without Snapshot Test)

Samuel Hutama
Dec 24, 2018 · 4 min read

Unit testing — one of the best way to prevent regression bugs from happening on a complex project. Each of the component in the project will be tested independently and thoroughly (the more cases the tests cover, the better).

In this post we will see how to create unit tests on a React component using Jest and Enzyme.

Prerequisites

The packages we need to install are:

  1. React, which also needs React-DOM
  2. Jest, and
  3. Enzyme, with Enzyme-Adapter-React (the adapter needed by Enzyme to test React component).

One way to install them is to use npm. Here is the repository I’ve prepared for this post (The installation steps are also included there):

In this post we will be using the unit tests in the repository above as our examples.

Our unit tests will NOT use Snapshot Test

Snapshot test is a test that will print the entire tested component’s content in a new file (called a snapshot, and the extension for this file is .snap). Whenever we made changes to the component and re-run this snapshot test, it will check the new content with the snapshot. If there is any difference, the test returns as a fail. When the test fails, we (the human) need to check which content is the correct one. If the new content is correct, then we update the snapshot. Otherwise, we need to fix the component so that the content match with the snapshot.

In other words, Snapshot test still needs us (human) to check whether the test succeed or fail. This is one of the reason why we don’t use Snapshot test. While the main reason is because of the fact that we can just tell the test to update its snapshot and the test will succeed, without even checking which content is the correct one .

Enzyme Shallow Test and Deep Test

We have two ways to test a React component: Shallow Testing and Deep Testing. Shallow Testing is a test that render a React component one level deep only. Its child components will not be rendered in Shallow Testing. On the other hand, Deep Testing is a test that render all of the sub-components of the tested component.

Shallow Testing can be done by using Enzyme’s shallow. While Deep Testing can be done by using mount. The code below shows how we prepare Enzyme to do these tests:

import {
configure,
shallow,
mount,
ShallowWrapper,
ReactWrapper
} from 'enzyme';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as Adapter from 'enzyme-adapter-react-16';
import { SomeComponent } from './someComponent';
describe('react unit tests', () => {
configure({
adapter: new Adapter()
});
describe('shallow tests', () => {
let shallowWrapper: ShallowWrapper;
beforeEach(() => {
shallowWrapper = shallow(<SomeComponent />);
});
});
describe('full DOM tests', () => {
let reactWrapper: ReactWrapper;
beforeEach(() => {
reactWrapper = mount(<SomeComponent />);
});
});
});

Before using Enzyme, it expects an adapter to be configured. The adapter corresponds to the library currently being tested. Since we are using React, we use Enzyme-Adapter-React. To configure an adapter, we call configure({ adapter: new Adapter() });.

Enzyme’s Shallow

Shallow testing a React component can be done by checking specific html element in the component to have the correct value. Let’s try shallow test this component called SomeComponent:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { ChildComponent } from './childComponent';
interface ISomeComponentProps { }export class SomeComponent extends
React.Component<ISomeComponentProps> {
render(): JSX.Element {
return (
<div>
<h1>Some Title</h1>
<p>First Paragraph</p>
<p className="random-class">
Second Paragraph with a class
</p>
<p id="randomId">Second Paragraph with an id</p>
<ChildComponent />
</div>
);
}
}

And below is the content of ChildComponent:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
interface IChildComponentProps { }export class ChildComponent extends
React.Component<IChildComponentProps> {
render(): JSX.Element {
return (
<div>
<p id="childId">Child component content</p>
</div>
);
}
}

There are several ways to check specific html element:

Find an element by its element name,

beforeEach(() => {
shallowWrapper = shallow(<SomeComponent />);
});
it('able to find an html element', () => {
expect(shallowWrapper.find('h1').html()).toContain('Some Title');
expect(shallowWrapper.find('p').length).toBe(3);
});

SomeComponent has a div containing an h1 element, 3 p element, and a ChildComponent sub-component. The ChildComponent has a div containing a p element.

Because shallow test only render one level deep and we are testing SomeComponent, only 3 p html element were found.

Find an element by its class,

it('able to find an html element by class', () => {
expect(shallowWrapper.find('.random-class').html())
.toContain('Second Paragraph with a class');
});

Find an element by its id,

it('able to find an html element by id', () => {
expect(shallowWrapper.find('#randomId').html())
.toContain('Second Paragraph with an id');
});

Notice that this find() method selector works in a similar way with jQuery selector.

Find a React component,

import { SomeComponent } from './someComponent';
import { ChildComponent } from './childComponent';
// ....it('able to find a React Component', () => {
expect(shallowWrapper.find(ChildComponent).length).toBe(1);
expect(shallowWrapper.find('#childId').exists())
.toBeFalsy();
});

We can find that ChildComponent is rendered in SomeComponent. But because we are doing shallow testing, we won’t find the html element rendered in ChildComponent (the one which has the id childId).

Enzyme’s Mount

The mount() method can be use to deep test a React component. Basically it behaves the same way as shallow(). The only difference is that mount() render all of the sub-components of the tested component.

describe('full DOM tests', () => {
let reactWrapper: ReactWrapper;
beforeEach(() => {
reactWrapper = mount(<SomeComponent />);
});
it('Child React Component html content would be rendered', () => {
expect(reactWrapper.find(ChildComponent).length).toBe(1);
expect(reactWrapper.find('p').length).toBe(4);
expect(reactWrapper.find('#childId').html())
.toContain('Child component content');
});
});

As we can see in the code above, the html element with childId id in ChildComponent is found.

Conclusion

So that’s it! We have covered how to do unit test on a React component, both shallow testing and deep testing, without using snapshot test. We usually do shallow test when we want to test a React component independently, so that the test can be more thorough. Ideally, the test needs to cover every possible cases for that component.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store