React, Enzyme, and Barbies... Oh my!

Valerie Kraucunas

(almost)

What i'll be covering

  • Brief Intro to Enzyme
  • React Testing Best Practices
  • Discuss Additional Testing Tools
  • Intro Fran's Barbie Dream Database

Please ask questions as they come to you.

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

and how the dream didn't make it to the party

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

INTRO TO ENZYME

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

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

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 skip incorporating jsdom

New Development

React v16

The environment is in a time of transition

npm i --save-dev enzyme-adapter-react-16

Best practices

TEST EARLY AND TEST OFTEN

Best practices

  • Start with .shallow()

 

  • Always refresh your wrapper variable between tests

 

  • Only pass wrappers the required props

 

  • If it is hard to test, re-write the component

 

  • Pick an assertion syntax and stick to it

Best practices

  • Explicit setup() instead of beforeEach()

 

const setup = propOverrides => {
  const props = Object.assign({
    activeCount: 0,
    onClearCompleted: sinon.spy(),
  }, propOverrides)

  const wrapper = shallow(<Footer {...props} />)

  return {
    props,
    wrapper,
    clear: wrapper.find('.clear-completed'),
    count: wrapper.find('.todo-count'),
  }
}

describe('count', () => {
  test('when active count 0', () => {
    const { count } = setup({ activeCount: 0 })
    expect(count.text()).toEqual('No items left')
  })
});

Best practices

Test double library!

npm i --save-dev sinon

Allows you to replace the difficult parts of your tests with something 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

Best practices

Sinon.js

describe('onBoundsChanged called for the first time', function() {
    const center = {lat: 37.7696044, lng: -122.41115960000001}

    before(function() {
      this.callback = sinon.spy();
      this.onCenterChanged = sinon.stub()
      this.wrapper = shallow(
        <DispensaryMapComponent
          dispensaries={dispensaries}
          location={{retrieved: true, coords: {lat: 37.71412, lng: -122.4734}}}
          onCenterChanged={this.onCenterChanged}
        />
      ).dive()
      this.component = this.wrapper.instance()

      sinon.stub(this.component, 'refreshClusters')
      this.component.onBoundsChanged({center: center, zoom: 16, bounds: boundsTest})
    })

Best practices

Husky

"Git hooks made easy"

npm install husky --save-dev


// package.json

{
  "scripts": {
    "precommit": "npm test",
    "prepush": "npm test",
    "...": "..."
  }
}
npm uninstall husky

fran's barbie dream database

Why?

fran's barbie dream database

Tools && Libraries

  • React & Redux
  • react-router-dom, redux-thunk
  • material-ui (ui kit)
  • axios

fran's barbie dream database

My Approach

  • MVP
  • Phase I
  • Phase II

fran's barbie dream database

When the Wheels Fell Off For Me

  1. Did not adhere to Testing Best Practice #1
  2. I did not ask enough questions this year
    1. Set up took a while
    2. redux-thunk
    3. material-ui
    4. create-react-app vs enzyme

fran's barbie dream database

React & Enzyme

React v16 and Enzyme v3 were released on September 26th.

Future of enzyme

  • Improve event simulation across all rendering methods
  • React Native testing improvements

Future of Fran's Barbie Dream Database

  • Batch adding
  • Uploading Images to AWS s3
  • Transform to a React Native application to utilize phone camera

Thank you!

Valerie Kraucunas

valeriekraucunas@gmail.com

vkraucunas

RESOURCES

React, Enzyme & Barbies

By Valerie Kraucunas

React, Enzyme & Barbies

"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)

  • 976