Enzyme Testing

Valerie Kraucunas

What i'll be covering

  • Intro to Enzyme
  • Rendering Methods
  • Best Practices
  • Upcoming Features of Enzyme

Please ask questions as they come to you.

If you have a better answer than I do, please contribute.

INTRO TO ENZYME

Started by Airbnb engineer Leland Richardson, since open sourced

Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components' output.

INTRO TO ENZYME

Benefits of using Enzyme

  • Unopinionated
  • jQuery style DOM traversal
  • Mocking out components to test is clean

Enzyme makes asking questions about the rendered output of your React components easy and intuitive by providing a fluent interface around rendered React components.

INTRO TO ENZYME

So uh... what am I supposed to be testing?

  • Is it a valid component?
  • Is everything rendering that you're expecting?
  • Checking props
  • Simulating events, such as a click

INTRO TO ENZYME

Getting Started

npm i --save-dev enzyme
npm i --save-dev react-addons-test-utils
npm i --save-dev react-dom
npm i --save-dev chai-enzyme 
npm i --save-dev jasmine-enzyme
npm i --save-dev jest-enzyme
npm i --save-dev should-enzyme

Optional Assertion Libraries

*

INTRO TO ENZYME

Example of basic test

import React from 'react';
import { shallow } from 'enzyme';
import ToDoList from '../components/ToDoList';
import ToDoItem from '../components/ToDoItem';

describe('<ToDoList />', () => {
  it('renders the entire list of items', () => {
    const items = [mockItem(), mockItem() /*, ... */];
    const wrapper = shallow(<ToDoList items={items} />);
    expect(wrapper.find(ToDoList)).to.have.length(items.length);
  });
});

INTRO TO ENZYME

Example of complex test

import React from 'react';
import { shallow } from 'enzyme';
import chai, {expect} from 'chai';
import { stub } from 'sinon';
import sinonChai from 'sinon-chai';
chai.use(sinonChai);

const FBButton4 = ({ likePage }) => {
  const onClick = () => {
    if (FB.like()) {
      likePage();
    }
  };
  return <button onClick={onClick}>Like this on Fakebook!</button>;
};

describe('<FBButton4 />', () => {
  it('will call our action because FB.like returns `true`', () => {
    const likePage = stub();
    const wrapper = shallow(<FBButton4 likePage={likePage} />);

    stub(FB, 'like').returns(true);

    wrapper.find('button').simulate('click');
    expect(likePage).to.have.been.called;
    FB.like.restore(); // This is important!
  });
});

Rendering methods

Shallow

Mount

Render

Rendering methods

Shallow

Purest unit testing option

No children rendered, to ensure that your tests aren't indirectly asserting on behavior of child components.

Fastest rendering method, works best on stateless components

Rendering methods

Mount

Full DOM rendering, including children

If you do not want to run your tests inside of a browser, the recommended approach to using mount is to depend on a library called jsdom which is essentially a headless browser implemented completely in JS.

Includes the most lifecycle testing

Rendering methods

Render

Renders static html, including children, fewest lifecycle methods covered

Uses Cheerio

Render is useful when you just want to assert on the DOM your component(s) render, lets you get around incorporating jsdom for mount

Best practices

  • Start with .shallow()
  • Always refresh your wrapper variable between tests
  • Only pass wrappers the required props for component to render
  • If you're having trouble writing a test for an existing component, consider rewriting the component to make it more testable
  • Pick an assertion syntax and stick to it

Best practices

What about React Native? 

npm i --save-dev react-native-mock

// test script in package.json
mocha --require react-native-mock/mock --recursive path/to/test/dir

React Native has many environmental dependencies that can be hard to simulate without a host device.

Best practices

Test double library!

npm i --save-dev sinon

Allows you to replace the difficult parts of your tests with something that makes testing simple.

Best practices

Test double library!

  • Spies, which offer information about function calls, without affecting their behavior
  • Stubs, which are like spies, but completely replace the function. This makes it possible to make a stubbed function do whatever you like — throw an exception, return a specific value, etc
  • Mocks, which make replacing whole objects easier by combining both spies and stubs

Future of enzyme

  • Integration tests
  • Improved CSS Selector Support
  • Improve event simulation
  • React Native testing improvements

Thank you!

Valerie Kraucunas

valeriekraucunas@gmail.com

vkraucunas

RESOURCES

Enzyme Testing

By Valerie Kraucunas

Enzyme Testing

"Untested code is broken code." Enzyme, the testing utility for React, is flexible, intuitive, and compatible with most test runners. When matched with a test double library like Sinon.js, Enzyme becomes capable of unit testing both components and reducers. Together we'll cover the tradeoffs of the different rendering methods provided from Enzyme, best practices for writing test files, and upcoming features of Enzyme. (ReactJS 2/2017)

  • 861