DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Testing in DevOps – The Basic and Critical Things You Need to Know
  • Mastering Unit Testing and Test-Driven Development in Java
  • Best Practices for Writing Unit Tests: A Comprehensive Guide
  • Exploring Unit Testing in Golang

Trending

  • No More Cheap Claude: 4 First Principles of Token Economics in 2026
  • Lambda-Driven API Design: Building Composable Node.js Endpoints With Functional Primitives
  • A Deep Dive into Tracing Agentic Workflows (Part 1)
  • Building a Zero-Cost Approval Workflow With AWS Lambda Durable Functions
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Unit Testing in ReactJS using Jest and Enzyme

Unit Testing in ReactJS using Jest and Enzyme

Using pure TDD best practices when developing an application ensures that they are performant when the code is written.

By 
Varun Prashar user avatar
Varun Prashar
·
Updated Jul. 12, 19 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
58.0K Views

Join the DZone community and get the full member experience.

Join For Free

According to Michael Feathers, “Any code that has no tests is a legacy code.” So as a developer it is your duty to avoid creating legacy code by using test-driven development (TDD).

There are many tools available for unit testing in ReactJS but we will be going through Enzyme and Jest.

What is Test Driven Development (TDD)?

Test Driven Development (TDD) is a programming practice which enables developers to write code only if an automated test has failed, thereby avoiding duplication of the code.

The primary aim of TDD is to write code which is clear and bug-free.

As a developer, you need to write tests for every small functionality of the application. It is a cyclic process and each cycle starts by writing a unit test.

Test Driven Development can easily be compiled in four easy steps:

  1. Write a test – First, you are going to write a test for every possible challenge.
  2. Run the test – Write the minimum code required to pass the test.
  3. Refactor your code – Improvise on the code quality
  4. Repeat the process – Now repeat this process for every new feature you introduce in the application.

Importance of Test-Driven Development (TDD)

Using TDD provides the following benefits:

  • You have a clear picture of what you are trying to build before you write the actual code
  • High test coverage;
  • Bug-free code;
  • Easy refactoring of the code;
  • It enables developers to write small test codes which are easy to debug.

Why Should You Use Test-Driven Development (TDD) for ReactJS?

If you have worked with ReactJS, then you probably know that code grows really fast in ReactJS. The code gets filled up with a lot of complex conditions due to service calls and change of state.

Every component of your React application that lacks unit tests becomes a legacy code which is very difficult to maintain. Although we can add unit tests after we create the production code, it will be very risky as some scenarios can get overlooked which will cause the issue at the production stage.

Setting Up The Environment for Test-Driven Development (TDD)

The most important thing to do first is to set up the environment for writing and running our tests.

We need testing frameworks like Jest and Enzyme for implementing our test codes.

Setting Up the Environment for TDD

For this tutorial, we are using the following versions –

{
  "react": "16.8",
  "enzyme": "3.9",
  "jest": "24.5.0",
  "jest-cli": "24.5.0",
  "babel-jest": "24.5.0"
}

Unit Testing With Jest

Jest is an open-source testing framework created by Facebook. Jest offers the best integration with ReactJS including a command line tool for test execution.

Jest offers a set of matchers which makes assertions easy to read and allows us to create mock functions with zero configuration.

Jest also offers “snapshot testing” to verify the component rendering result.

For unit testing with Jest, first, install Jest using the following command –

$ npm install -save-dev jest

After installing Jest, add the following lines to your package.json file –

{
 "scripts": {
  "test": "jest",
  "test:watch": "npm test -- --watch"
 }
}

Unit Testing with Enzyme

Enzyme is also an open-source testing framework which is maintained by Airbnb. It is easier to assert, manipulate, and traverse React components in Enzyme.

You can use any of the testing frameworks but it is generally better to go with Jest as it offers all the required tools for unit testing and it is being used by Facebook in all its javascript codes.

For unit testing with Enzyme, first, install Enzyme using the following command:

$ npm i-save-dev enzyme

Enzyme API

To render React components and to retrieve specific nodes, you need to focus on Enzyme API. There are three ways to render a React component.

Shallow Rendering

Shallow rendering is used to ensure that your tests aren’t asserting on the behavior of child components and is also useful to constrain yourself from testing a component as a unit.

Import

import { shallow } from 'enzyme';

Full Rendering

Full rendering, or Full DOM rendering, is best for use cases that require interaction between components and DOM APIs. Full rendering is also useful in use cases where the test components are wrapped in higher order components.

For Full rendering, it is required that the full DOM API is available at global scope. So you need a browser environment to run Full DOM rendering.

If you do not want to run the test inside a browser you can use jsdom library which is a headless browser implemented in JavaScript.

As in full rendering, components are actually mounted in the DOM, which means they can affect each other (if they are using the same DOM).

Import

import { mount } from 'enzyme';


Static Rendering

Static rendering uses the render function to generate HTML from a React tree.

The render function returns the similar output when compared with other Enzyme rendering methods such as shallow and mount but it uses a third-party library Cheerio for parsing and traversing HTML.

Import

import { render } from 'enzyme';


Creating a React.js Component Using TDD

The very first step is to create a failing test which will try to render the ReactJS component using shallow rendering:

// ComponentName.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ComponentName from './ComponentName;
describe("ComponentName", () => {
  it("should render my component", () => {
    const wrapper = shallow(<ComponentName />);
  });
});

So when you run the test, you will get the following error:

"ReferenceError: ComponentName is not defined."

After creating the failing test, we will create the ReactJS component using the basic syntax which will make the test pass:

// ComponentName.js
import React from 'react';

export default class ComponentName extends React.Component {
  render() {
    return <div />;
  }
}


Next, we need to make sure that our ReactJS component renders a predefined UI layout using the Jest toMatchSnapshotfunction.

Jest will automatically create a snapshot file [myTestFileName].snap under _snapshots_ folder. This file basically represents the UI layout we are expecting from the rendering of our ReactJS component.

However, as we are trying to implement a pure Test Driven Development (TDD), we first need to create the file and then call the toMatchSnapshotfunction.

This doesn’t mean that executing the toMatchSnapshotfunction first and then seeing the results in the snapshot file is not a valid option.

However, to execute a pure TDD, we need to learn the structuring in snapshot files.

So first, we create the ComponentName.test.js.snap file.

//__snapshots__/ComponentName.test.js.snap
exports[`ComponentName should render initial layout 1`] = `
Array [
<div>
    <input
         type="number"
    />
</div>,
]
`;


After this, we create the unit test that will validate that the snapshot matches the component child elements.

// ComponentName.test.js
...
it("should render initial layout", () => {
    // when
    const component = shallow(<ComponentName />);
    // then
    expect(component.getElements()).toMatchSnapshot();
});


Now we consider that components.getElements is the result of the render method.

Now we pass these elements to the expect method so that we can run the verification process against the snapshot file.

Once you execute the test, you will get the following error:

"Received value does not match stored snapshot 1."


Expected:
 - Array [
    <div>
        <input type="number” />
     </div>,
    ]
Actual:
+ Array []


The above error states that the result from  component.getElements does not match the snapshot. So we make this test pass:

// ComponentName.js
import React from 'react';
export default class ComponentName extends React.Component {
  render() {
    return <div><input type="number" /></div>;
  }
}


The next step is to add functionality to input by executing a function when its value changes.

We first make changes to snapshot to make the test fail:

//__snapshots__/ComponentName.test.js.snap
exports[`ComponentName should render initial layout 1`] = `
Array [
<div>
    <input
         onChange={[Function]}
         type="number"      
     />
</div>,
]
`;


Jest will automatically sort the props or attributes in the expect function alphabetically before verifying it against the snapshot.

After test execution, we get the following error:

Received value does not match stored snapshot 1.
Expected:
 - Array [
    <div>
        onChange={[Function]}
        <input type="number”/>
     </div>,
    ]
Actual:
+ Array [
    <div>
        <input type=”number”  />
     </div>,
    ]

Now, to make this test pass, we will add an empty function to onChange.

// ComponentName.js
import React from 'react';

export default class ComponentName extends React.Component {
  render() {
    return <div><input
      onChange={() => {}}
      type="number" /></div>;
  }
}


We need to make sure that the component state changes after the onChange event are dispatched. To do this, we create a new unit test which will call the onChange function by passing an event.

Then we verify that the component state contains a key named input.

// ComponentName.test.js
...
it("should create an entry in component state", () => {
    // given
    const component = shallow(<ComponentName />);
    const form = component.find('input');
    // when
    form.props().onChange({target: {
       name: 'myName',
       value: 'myValue'
    }});
    // then
    expect(component.state('input')).toBeDefined();
});

Now we get the following error:

"Expected value to be defined, instead received undefined"

So now we make the test pass by setting input in the component state

// ComponentName.js
import React from 'react';

export default class ComponentName extends React.Component {
  render() {
    return <div><input
      onChange={(event) => {this.setState({input: ''})}}
      type="number" /></div>;
  }
}

Now we need to make sure that the value is set in the new state. We will get this value from the event. So we create a test to make sure that the state contains this value.

// ComponentName.test.js
...
  it("should insert value in components state with the events value", () => {
    // given
    const component = shallow(<ComponentName />);
    const form = component.find('input');
    // when
    form.props().onChange({target: {
      name: 'myName',
      value: 'myValue'
    }});
    // then
    expect(component.state('input')).toEqual('myValue');
  });
 ~~~


Not surprisingly, we get the following error:

~~

Expected value to equal: “myValue”

Received: “”

Now we make this test pass by getting value from the event and setting it as the input value.

// ComponentName.js
import React from 'react';

export default class ComponentName extends React.Component {
  render() {
    return <div><input
      onChange={(event) => {
         this.setState({input: event.target.value})}}
      type="number" /></div>;
  }
}


Now as all the tests have passed, we can now refactor our code.

// ComponentName.js
import React from 'react';

export default class ComponentName extends React.Component {
  updateState(event) {
    this.setState({
        input: event.target.value
    });
  }
  render() {
    return <div><input
      onChange={this.updateState.bind(this)}
      type="number" /></div>;
  }
}


Summary

From the above example, it may seem that many of the steps are unnecessary and can be skipped, but to really execute Test-Driven Development in its purest form, I will suggest you to avoid skipping any step.

Using a less strict TDD process is perfectly valid as it is a very difficult technique to master but it is definitely worth doing.

TDD must be adopted by every developer as it increases your productivity and also improves the code quality, and applications developed using TDD technique are more modular and flexible.

unit test Test-driven development Open source Snapshot (computer storage)

Published at DZone with permission of Varun Prashar. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Testing in DevOps – The Basic and Critical Things You Need to Know
  • Mastering Unit Testing and Test-Driven Development in Java
  • Best Practices for Writing Unit Tests: A Comprehensive Guide
  • Exploring Unit Testing in Golang

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook