Valerie Kraucunas
(almost)
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
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.
Benefits of using Enzyme
Enzyme makes asking questions about the rendered output of your React components easy and intuitive
So uh... what am I supposed to be testing?
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);
});
});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!
});
});Shallow
Mount
Render
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
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
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
React v16
The environment is in a time of transition
npm i --save-dev enzyme-adapter-react-16
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')
})
});Test double library!
npm i --save-dev sinonAllows you to replace the difficult parts of your tests with something simple.
Test double library!
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})
})Husky
npm install husky --save-dev
// package.json
{
"scripts": {
"precommit": "npm test",
"prepush": "npm test",
"...": "..."
}
}npm uninstall huskyWhy?
Tools && Libraries
My Approach
When the Wheels Fell Off For Me
React & Enzyme
React v16 and Enzyme v3 were released on September 26th.
Valerie Kraucunas
valeriekraucunas@gmail.com
vkraucunas