Skip to content

Instantly share code, notes, and snippets.

@filipeamoreira
Forked from joshdover/README.md
Created July 14, 2016 00:09
Show Gist options
  • Select an option

  • Save filipeamoreira/38d712e0616c69d3ad9870af061fc670 to your computer and use it in GitHub Desktop.

Select an option

Save filipeamoreira/38d712e0616c69d3ad9870af061fc670 to your computer and use it in GitHub Desktop.
Idiomatic React Testing Patterns
import { expect } from 'chai';
import sinon from 'sinon';
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import MyComponent from './MyComponent';
/*
* Pattern to be used for testing instance methods of components. These should not be used to test impementation details.
* Examples of good applications of this pattern:
* - Testing interactions with a stateful DOM API (eg. iframe). NOTE: components should not interact with DOM APIs
* that are not related to visual display.
* - Test interactions with an external UI library (eg. an image editor like Aviary)
*/
describe('MyComponent', () => {
const getComponent = (props = {}) => {
props = Object.assign({
onChange: sinon.spy(),
}, props);
const node = document.createElement('div');
// Notice the different rendering method here
const component = ReactDOM.render(
<MyComponent {...props} />
), node);
return Object.assign(props, { component });
};
describe('myMethod', () => {
it('returns some value', () => {
const { component } = getComponent();
expect(component.myMethod()).to.equal('some value');
});
});
});
import { expect } from 'chai';
import sinon from 'sinon';
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import MyComponent from './MyComponent';
/*
* Pattern to be used to assert basic rendering expectations, including how props change the output.
*/
describe('MyComponent', () => {
const getComponent = (props = {}) => {
// Any test can override the default props by passing an object to the getComponent function
props = Object.assign({
onChange: sinon.spy(),
}, props);
const component = ReactDOM.findDOMNode(TestUtils.renderIntoDocument(
<MyComponent {...props} />
));
return Object.assign(props, { component });
};
it('renders a h1 for title prop', () => {
const { component } = getComponent({ title: 'My Label' });
expect(component.querySelector('h1').innerText).to.equal('My Label');
});
});
import { expect } from 'chai';
import sinon from 'sinon';
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import MyComponent from './MyComponent';
/*
* To be used when testing a component that is _NOT_ pure (uses this.state) OR when testing lifecycle hooks
* (eg. componentDidUpdate). This is accomplished by re-rendering the the component manually and then asserting
* expectations.
*/
describe('MyComponent', () => {
const getComponent = (props = {}) => {
props = Object.assign({
onChange: sinon.spy(),
}, props);
const node = document.createElement('div');
// Notice the different rendering method here
const component = ReactDOM.render(
<MyComponent {...props} />
), node);
return Object.assign(props, { component, node });
};
context('when clicked', () => {
it('adds some-class', () => {
const props = getComponent();
// Do some action that changes internal state
TestUtils.Simulate.click(props.component);
// Re-render (you can also change props here)
ReactDOM.render(<MyComponent {...props} />, props.node);
expect(component.className).includes('some-class');
});
});
});
import { expect } from 'chai';
import sinon from 'sinon';
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import MyComponent from './MyComponent';
/*
* Pattern to be used to assert pure interaction expectations that do not require any lifecycle hooks or internal state.
*/
describe('MyComponent', () => {
const getComponent = (props = {}) => {
props = Object.assign({
onChange: sinon.spy(),
}, props);
const component = ReactDOM.findDOMNode(TestUtils.renderIntoDocument(
<MyComponent {...props} />
));
return Object.assign(props, { component });
};
context('when the component is changed', () => {
it('calls onChange', () => {
const { component, onChange } = getComponent();
const inputNode = input.querySelector('input[type=text]');
TestUtils.Simulate.change(inputNode, { target: { value: 'new' } });
expect(onChange.calledWith('new')).to.be.true;
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment