Testing React Components with Jest and Enzyme
In the last article, we scratched the surface of unit testing with Jest in React. The problem with that article is that it’s a bit on the Hello World level and not nearly enough to really be able to start testing. When we write tests, we have a lot more than a simple, stateless component. Often we’ll have complex components comprised of other components with much more interesting behaviors.
One of the most helpful utilities available to us in Jest is the component enzyme which is free (at the moment anyway). It’s so important that it even has its own place in the create react app documentation along with Jest. In general, this component helps us render components and see how they behave. But even more than that, we can commit to the structure of a component and its output.
So let’s get to testing! Installing enzyme is easy as could be. In your React application, install the enzyme module with the following command:
npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer
These are modules that go with enzyme. Now we need to make a settings file. Make a file called src/setupTests.js. This is a settings file that you can really go wild with, but for now this is what we’ll put inside of it. Remember that configure is an object that we can do a lot with. But for now we’ll just do this:
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
From here we can check. In the last article, I talk about a pretty dumb component I called MyComponent. It looked like this:
import React from 'react';
class MyComponent extends React.Component {
render() {
return <p>Hello world!</p>
}
}
export default MyComponent;
And its test looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import MyComponent from './MyComponent';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<MyComponent />, div);
expect(div.innerHTML).toEqual('<p>Hello world!</p>');
});
Now let’s turn this test into one that’s a bit smarter and more resistant. How? With enzyme of course. Take note:
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';
it('renders without crashing', () => {
const myComponent = shallow(<MyComponent />);
expect(myComponent.contains(<p>Hello world!</p>)).toEqual(true);
});
So what do we have here? We create the element using shallow. What does that mean? If a component has another component inside of it, they won’t render! This is very important in unit testing because these tests need to be completely isolated (if I want the child components to render as well I can use mount). Second, I’m using syntax with JSX which is simple and easy. But there’s a lot more! There's a full API to enzyme that lets me do a lot more interesting things like traversing and find with the same syntax as… jQuery. I swear it’s true. Here’s an example in which I only check the text:
it('renders without crashing', () => {
const myComponent = shallow(<MyComponent />);
expect(myComponent.text()).toContain('Hello');
});
Now it seems a good time to talk a bit about the proper structure of a test. Before every test, we should have describe which contains a whole bunch of other tests. Also, we need before which has preparations for tests. For example, if I want to examine the component, my test file will look like this:
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';
let element; // "global element to be populated in the beforeEach"
// The description of the test suite
describe('MyComponent Component is working normally', () => {
// Setup
beforeEach(() => {
element = shallow(<MyComponent />);
});
it('Checks if there is hello', () => {
expect(element.text()).toContain('Hello');
});
it('Checks if there is world', () => {
expect(element.text()).toContain('world');
});
});
So what we’ve got here is describe which wraps everything and is basically a name for the set of tests. Then we’ve got beforeEach which runs before all the tests. In this case, we’re creating the component and populating it inside a global variable which we check. And that’s it! Pretty sweet!
If you’ve already seen automated testing and unit tests, you’re probably thinking that this is really similar to Jasmine. Here, I don’t really have much to contribute other than to say that you should use enzyme. But if this whole world of automated testing is new to you, stop whatever it is that you’re doing. Yes, yes, just stop and then run create react app and put in MyComponent and write the test above for it. Automated tests are critical for any and every application.
OK, so we’ve seen the Hello World example. Let’s expand upon this a bit. We’ll add props to our component. How do we do this in the real world? Just like this. First the component, which shouldn’t be any trouble to understand if you went through the last article:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
render() {
return <p>Hello {this.props.greeting}!</p>
}
}
export default MyComponent;
And how do the tests look in the real world? If I want to add props, the best way to do it is to create an object of all the props and then transplant it into a component like so:
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';
let element; // global element to be populated in the beforeEach.
let props; // "props" is global because I need to access it.
// The description of the test suite
describe('MyComponent Component is working normally', () => {
// Setup
beforeEach(() => {
// Here I put the props, in this case greeting
props = {
greeting: 'Galaxy',
};
element = shallow(<MyComponent {...props} />);
});
it('Checks if there is hello', () => {
expect(element.text()).toContain('Hello');
});
it('Checks if there is world', () => {
expect(element.text()).toContain(props.greeting);
});
});
Notice that this code seems a bit confusing at the beginning. Maybe due to the syntax with the three dots. That’s just destrdeconstructucture which we learned about once in an ES6 article. I’m using it here in order to take the entire props object and put it into the component. Since my props is in the upper scope of the test, I can use it even in the secondary test without needing to use a special text string.
This test is pretty simple, but the structure is already reminiscent of what we would use in the real world. There is one other significant usage to enzyme, and we still need to talk about mocking. All that and more in a future article.
Previous Article: Automated Testing in React: Intro | Next article: Real-world Units Tests in React with Jest and Enzyme |
About the author: Ran Bar-Zik is an experienced web developer whose personal blog, Internet Israel, features articles and guides on Node.js, MongoDB, Git, SASS, jQuery, HTML 5, MySQL, and more. Translation of the original article by Aaron Raizen.
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment