Enzyme
NYC Bootcamper's Anonymous Meetup
August 6th, 2018 @ American Express
Tommy York, http://www.tommy-york.com
Summary
- Testing utility, designed for React
- Mimicks jQuery's API for DOM manipulation and traversal
- Unopinionated about your test runner or library:
chai-enzyme,jasmine-enzyme,jest-enzyme,should-enzyme, andexpect-enzyme
- Already included in
create-react-app!
Setup
1tyork% npm i --save-dev enzyme enzyme-adapter-react-16
Then:
1import Enzyme from 'enzyme';2import Adapter from 'enzyme-adapter-react-16';34Enzyme.configure({ adapter: new Adapter() });
Usage
Common Usage
- Shallow Rendering
- Full DOM Rendering
- Static Rendered Markup
Plus:
- Testing static methods on the class
- Testing methods on a rendered component
- More!
The Component
I wrote tests for a tooltip component we use to render a wide range of content for different Canadian AMEX Cards.

Setting up some test props
1const props = {2 children: <div>3 <span>Example</span>4 <span>Children</span>5 </div>,6 clickableText: 'Clickable text.',7 tooltipPopupText: 'Tooltip text.',8 className: '',9 styles,10};
And testing our component...
1const shallowTooltip = shallow(<Tooltip {...props} />);23const mountedTooltip = mount(<Tooltip {...props} />);45const staticallyRenderedTooltip =6 render(<Tooltip {...props} />);
Types of Rendering
- Shallow
- Full DOM
- Static
Shallow Rendering
Shallow rendering takes the result of the component's render method, and gives us a wrapper object, which allows us to do basic traversal.
However, Kent C. Dodds' take:
With shallow rendering, I can refactor my component's implementation and my tests break. With shallow rendering, I can break my application and my tests say everything's still working.
Shallow Rendering, Pt. 2
You don't get:
- React lifecycle methods (
componentDidMount,componentWillReceiveProps, etc.) - The ability to interact with DOM elements
- The react elements within the component - you only render one component deep.
Shallow Render, Pt. 3
Avoid the temptation to solely write tests for methods, without also testing for the actual user interaction that triggers those methods.
Full DOM Rendering / mounting
- JSDOM is a simple JavaScript browser
mountAPI requires a DOM, so JSDOM is used when there's no browser environment (Node!).
Static Rendering
Enzyme also supports rendering your component to HTML, then traversing it with the HTML traversal library Cheerio.
Like JSDOM, Cheerio does not produce a visual rendering. However, unlike JSDOM, Cheerio does not:
- Apply CSS
- Load external resources
- Execute JavaScript
Test Coverage
Among other things, we're going to want to test a range of functionality, including:
- Snapshots
- User interaction with the component
- Any static methods on the tooltip
- The click event listener added to the window, used to close the tooltip when users click outside of the tooltip.
Snapshots
We can test our component with a saved "snapshot" from a previous test run.
1it('should match its snapshot', () => {2 const tooltip = mount(<Tooltip {...props} />);3 expect(tooltip).toMatchSnapshot();4});
You can update the snapshot from the command line if you've decided it should change.
User Interaction (using mount)
1it('should open / close', () => {2 const tooltip = mount(<Tooltip {...props} />);345 tooltip.first('span').simulate('click');6 expect(tooltip.state('visible')).toBe(true);
Cool Functionality
Test Class Methods
If you're using Jest and Enzyme, you can use jest.spyOn to test function calls, much like you would with Sinon.js.
1const tooltip = mount(<Tooltip {...props} />);23jest.spyOn(4 Tooltip.instance(),5 'addResizeListener'6);78tooltip.first('span').simulate('click');9expect(spyOnAdd).toBeCalled();
Test window events
We can test window events as well, using standard window properties (innerWidth and innerHeight) and our ability to send arbitrary events through JSDOM:
1window.resizeTo = (width, height) => {2 window.innerWidth = width;3 window.innerHeight = height;4 window.dispatchEvent(new Event('resize'));5};
