React fast, use Enzyme

While ReactJS is growing and becoming lead UI library, we need also an easy utility to test it. Yes, ReactJS comes with its TestUtils, developed by the React team, but also in their documentation they recommend using AirBnB’s Enzyme for easier testing.

Before we talk about Enzyme, let’s understand what React TestUtils gives us. Because of ReactJS unique DOM manipulation, testing it with the common frameworks like Jasmine for example, is more complicated. Facebook React team have developed their internal testing utility to test the DOM manipulations easier. The drawback of the TestUtils is its over complexity of methods, and I’ll explain…

Let’s say we want to find a DOM element in our page, an easy and common requirement, right? TestUtils provide us the scryRenderedComponentsWithTag method. It’ll so the work.. BUT! only if we’re looking for only one element. What happens if we have more than one element of the same type in our page? TestUtils provide us a different method for that: findRenderedDOMComponentWithTag. At that point the developer asks himself “Why do I need 2 different methods? I used to do it with jQuery’s ‘find’ method!”.

Ta da! This is what Enzyme is here for - to simplify the TestUtils methods over complexity. While being based on React TestUtils, Enzyme provide a jQuery like APIs to make React DOM manipulation more intuitive & flexible, and doesn’t require the developer to use different method for each DOM action. If we were using the DOM element search example for TestUtils, with Enzyme the only thing we’ll have to do is to use find().

Let’s see some code.

This is the TestUtils way:

it('should update clicked in component state to true on button click', () => {
   const component = TestUtils.renderIntoDocument(<ButtonComponent />);
   const buttonComp = TestUtils.findRenderedDOMComponentWithClass(component, 'btn');
   const buttonNode = ReactDOM.findDOMNode(buttonComp);
   TestUtils.Simulate.click(buttonNode);
   expect(buttonComp.state.clicked).to.equal(true);
});

and this is the Enzyme way:

it('should update clicked in component state to true on button click', () => {
   const component = mount(<ButtonComponent />)
   component.find('.btn').simulate('click');
   expect(component.instance().state.clicked).to.equal(true);
});

ignore the mount, simulate methods for now, we’ll get into it later. Just notice that what TestUtils does in 5 lines, Enzyme is doing with only 3. It’s only 2 lines in this example, but when it comes to larger tests scale, it can save you LOTS of code lines and complexity.

Now, let’s explain some basics about Enzyme. I’m not going to write a full tutorial how to use Enzyme, they have a pretty good documentation for that (http://airbnb.io/enzyme/), but I’ll show some basics so you’ll have a general feeling of how easy & intuitive Enzyme APIs are.

Selectors

As I noted before, Enzyme is mimicking jQuery’s APIs, so if you are familiar with jQuery, this part should be pretty easy. Just use.. find(). For example, if we want to find an element with the class .foo, just call:

component.find('.foo');

Same for elements with a foo property:

component.find([title=foo]);

Easy.

Element properties

Every ReactJS developer knows its famous props. Right? Enzyme knows these props too. Let’s start with an easy one, just reading the element’s id prop:

component.find('.btn').node.props.id;

But we can also run onClick prop manually:

component.find('.btn').node.props.onClick({target: {value: 'value'}});

This feature is pretty strong when we’re running some flow in our test which requires a button click. We cannot really click on the button, but we can imitate it.

Arrays

Handling arrays with Enzyme is pretty straight forward. We get an array, and ‘asking’ for the item in a specific index: In this example, we’re running a ‘find’ selector to get all the elements with the .btnclass. It is very common that there will be more than one element with this class on our page, so we will get an array holding all the elements the selector found. Now if we want only the second element found, we will ‘get’ it:

component.find('.btn').get(1);

Quick note: The array is Zero based. I hope you’re not surprised by that.

Simulating

In the beginning of this post, I was showed the differences between TestUtils & Enzyme, and I used a click simulation to do it. This is a very powerful feature in ReactJS tests, after all we’re building user interfaces which requires a user interactions. Therefore, we need to test those interactions. We can do it easily by simulating those interactions. For example, if we want to simulate a user click on a button:

component.find(button).simulate('click');

Interactions are not all about clicking. Input fields are also an interaction, and it can be simulated very easily too:

component.find('input').simulate('keyDown', {keyCode: 89});

Here we simulate e keyDown event, and providing the input field the keyCode 89, which is the letter ‘z’. We can simulate every keyboard key, even arrow keyCodes (37, 38, 39, 40), page up/down (33, 34), numlock (144), well.. you got the idea.

If we want to just simulate a change, let’s say an input field change, which will cause the onChange to be called, we can use:

component.find('input').simulate('change');

Summary

I was trying to show you why using Enzyme can be much easier than React TestUtils, and how it will make your tests shorter & easier to read. AirBnB’s Enzyme is well documented, I encourage you to give it a chance.

That’s it.

Cheers, Erez.

Tikal: Erez Carmel
Twitter: @erezcarmel
LinkedIn: Erez Carmel

Sr.Frontend Developer

Frontend Group