-
-
Save filipeamoreira/38d712e0616c69d3ad9870af061fc670 to your computer and use it in GitHub Desktop.
Idiomatic React Testing Patterns
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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'); | |
| }); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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'); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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'); | |
| }); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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