Testing React applications with Jest and Enzyme

Testing is an essential part of software development, ensures maintainability of code. Writing automatic tests helps to locate new bugs, improve quality and perfectly complements manual testing.

In this article we will go through the set up and some of most common ways to test React application developed with create-react-app (CRA) 2.1.3 version.

To get started, let me introduce today’s heroes:

  1. Jest – a JavaScript testing framework by Facebook. We are using CRA where Jest is installed automatically. Its job is to take all test files in our project, run the tests and display results in terminal. Jest can be used with non-react applications.
  2. Enzyme – is a testing tool developed and managed by Airbnb. Enzyme uses several of the utilities provided by React to build its API. Enzyme works only with React.

SET UP

  • Setting up React application with CRA
create-react-app testing
cd testing
npm start
  • Setting up Enzyme
npm install --save enzyme enzyme-adapter-react-16

Put your attention to version of React which you are using. Here we have 16, but Enzyme has adapters for all versions. Here you will find details: Enzyme installation guide.

To finish configuration, we have to create a new file called setupTests.js under src directory, so we can use Enzyme in any of test files. Name is very important here.

setupTests.js

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({adapter: new Adapter() });

This is it! Installation is behind us.

FUNCTIONS IN ENZYME

We will use the functions below. They will create instances of our components and return back objects which we can use to write tests

  • Static – renders the given component and returns plain HTML
  • Shallow – most basic version, it renders only given component without children. Perfect for unit tests
  • Full DOM which renders the components with all children, here we are able to interact with components

TEST STRUCTURE

Our tests will be placed in a new directory __tests__

It is a good habit to organize tests in this way. Jest will run all files located inside.

To make it easy to recognize which test pertain to which file, we are describing them in the same way as tested file: .test.js at the end.

Our tests will always be in schema:

it ('test description', function which contain logic of our test);

Function inside our test can contain few expectations, where we can describe the value which we expect to see.

FINALLY TEST!

Below is the content of two simple components:

List.js

import React, { Component } from 'react';


class List extends Component {
    render() {
        return (
            <form>
              <h3>Add new element</h3>
              <textarea />
              <div>
                <button>Save</button>
              </div>
            </form>
        );
    }
}

export default List;

App.js

import React from 'react';
import List from './List'

export default()=>{
    return (
        <div><List /></div>
    );
};

Let’s simply test rendering List.js component. We will use shallow function as we don’t need to render its children. If component is working correctly test will pass, otherwise it will fail.

List.test.js

import React from 'react';
import { shallow } from 'enzyme'; 
import List from '../List';

it('renders without crashing', () => {
  shallow(<List />);
});

Now check if the test will pass by typing in terminal

npm test

Great! Our fist test works. To end testing mode just press ctrl+c.

Now we will check the components instance.We want to check if List.js component is located in App.js.

App.test.js

import React from 'react';
import { shallow } from 'enzyme'; 
import App from '../App';
import List from '../List';

it('shows the list', () => {
  const wrapped = shallow(<App />);
  expect(wrapped.find(List).length).toEqual(1);
});

const wrapped means that the object which we will have from shallow(<App />) is a wrapped version of App component.

And both tests passed!

In similar way as above we can check if our component contains button and input area:

List.test.js

import React from 'react';
import { mount } from 'enzyme'; 
import List from '../List';

it('contains button and text area', () => {
  const wrapped = mount(<List />);
  expect(wrapped.find('textarea').length).toEqual(1);
  expect(wrapped.find('button').length).toEqual(1);
});

Find is very powerful in tests. Thanks to it, we can detect every class, HTML element, attribute syntax, prop or object property selector and check if it meets our expectations.

Now the question is, how to test…. a test?

We can check it by changing expected value to an incorrect one. Let’s try to pretend that we don’t have a button in List.js, we put value 0 instead of 1 in test file. Now test should fail

List.test.js

it('shows button', () => {
    const wrapped = shallow (<List />);
    expect(wrapped.find('button').length).toEqual(0);
});

Indeed it happened, Jest shows us exactly what goes wrong.

CONCLUSION

Jest and Enzyme are well integrated and provide flexible testing abilities. Configuration is very easy what is a great advantage. We did not delve into the specific methods but now surely we are able to evaluate Jest’s and Enzyme’s efficiency.

Origin: www.linkedin.com

All articles