Unit Testing React Components Using Enzyme and Jest Testing Frameworks
Tags: react, webdev, beginners
Published: 2020-08-25 10:30:29

In this tutorial, we will be writing unit test for  a basic todo application using jest and react.

Let’s get started.

---

##Jest
Jest is a JavaScript testing framework designed to ensure correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar and feature-rich API that gives you results quickly.
Jest is well-documented, requires little configuration and can be extended to match your requirements. For more information on Jest checkout its official documentation.
[Getting Started](https://jestjs.io/docs/en/getting-started)

---

## Enzyme
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 checkout Enzyme official documentation.
[Getting Started](https://enzymejs.github.io/enzyme/)

---

## Setup

In this tutorial we will make use of the create-react-app CLI tool to setting up our project. 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 dont have create-react-app install type the following command in the terminal to install it globally.


    npm install -g create-react-app

---

### Sponsored:

[![React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6be3k0c5qa8udbdbqcsx.jpg)](https://adminmart.com/templates/react/?ref=6)

---

### Install Enzyme:


    npm install --save-dev enzyme enzyme-adapter-react-16 enzyme-to-json

The Jest testing framework is by default bundled into create-react-app.

In the src folder, create a tempPolyfills.js file with following content. This is necessary for testing on older browsers.

    const raf = global.requestAnimationFrame = (cb) => {
      setTimeout(cb, 0);
    };
      
    export default raf;

In the src folder, create a setupTests.js file with 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 todo app.

![image](https://paper-attachments.dropbox.com/s_6D523E6DECCD35424973F72AE8A256E2FB486C8793A382FECB781D4352B758B3_1595020481043_freesnippingtool.com_capture_20200717221355.png)


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 binded 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 todo 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 todo items we need to iterate over each todo 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 and Enzyme

create-react-app sets up a dummy test for us in the app.test.js file. Lets execute the initial test for our project with the following command in our project folder.


    npm test
![image](https://paper-attachments.dropbox.com/s_6D523E6DECCD35424973F72AE8A256E2FB486C8793A382FECB781D4352B758B3_1595023328568_freesnippingtool.com_capture_20200717230109.png)


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 enzyme.  The shallow() function will be used to shallow render components during 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 the component
• Traverse the virtual DOM, picking out the first th element
• Assert that the th 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 method is contains(). It is used to assert the presence of an elements 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 it 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 describe will be run *after* the before Each declared in the outer context. Therefore, the wrapper will already be shallow rendered by the time this beforeEach runs. As expected, this beforeEach will only be run for it blocks inside our inner describe block

We will use the simulate method to simulate user interactions. 

The simulate method accepts two arguments:

1. The event to simulate (like'change'or'click'). This determines which event handler to use(like onChange or onClick).
2. 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:

1. The user clears the input field
2. 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 describe “the user populates the input” by nesting our new describe 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 value to a blank string.We’ll write one assertion: that the button is disabled again.
When ever the field is empty the button should be disabled.

Now, we can verify that all our tests pass.


![image](https://paper-attachments.dropbox.com/s_6D523E6DECCD35424973F72AE8A256E2FB486C8793A382FECB781D4352B758B3_1595167779482_freesnippingtool.com_capture_20200719150913.png)


Next, we’ll simulate the user submitting the form.

## Simulating a form submission

After the user has submitted the form, We’ll assert that:
1. The new item is in state (items)
2. The new item is inside the rendered table
3. The input field is empty
4. 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 submit, 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 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 contains 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('');
    });

Finally, 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.

## Conclusion
In total, so far we’ve learn 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 Jest and Enzyme test frameworks.

We would like to thank WrapPixel and AdminMart for offering this tutorial to us. They offer high quality free and premium React Admin Dashboard and Website Templates.
[WrapPixel](https://www.wrappixel.com/templates/category/react-templates/?ref=232) and [AdminMart](https://adminmart.com/templates/react/?ref=6).