Unit Testing in React
General advices
Why Test
Main reasons:
- to make sure the app works as it should
- gives more confidence
Advantages:
- code refactoring without breaking anything
- adding new features, tweaking existing ones
- make sure you don't break some other part of the app
What's Worth Testing
- start with high-value items
- anything that accepts user input
- form validation
- error handling
- edge cases
- utility functions
What to Test
- that the comp. renders (without errors)
- that it renders the expected things
- all the variables in state
- className if it depends on state
- styles if they depend on state
- conditionally rendered children
- events
- the callback was called with the correct args
- edge cases
- especially when working with list of items
- different values for the props
- null, undefined, empty array/object
How to Test
Shallow rendering:
- renders only one level of components
- makes sure children don't affect assertions
- decouples the components
Using mount:
- needs a browser env.
- can be used to test the lifecycle of the comp.
Testing Redux
- the actions and reducers should be tested separately
- reducers are easy to test because they are pure functions
- for actions we need to mock the REST library
- the actions should be injected in the comp. using DI
- something like InversifyJS
- when testing a comp, check that the action was called with the correct arguments
Useful Patterns
// finding a HTML element
const wrapper: ShallowWrapper = shallow(<App/>);
expect(wrapper.find("h1")).to.have.length(1);
// finding a React component
expect(wrapper.find(ProductList)).to.have.length(1);
// contains the an element
expect(wrapper.contains(<span className="num-items">{0}</span>)).to.equal(true);
// check a click event
const noneRadio: ShallowWrapper= wrapper.find("input[value='none']");
noneRadio.simulate("change", {target: {checked: true}});
expect(onSortSpy.called).to.equal(true);
expect(onSortSpy.calledWith("none")).to.equal(true);chai-enzyme
// class name
expect(wrapper.find('span')).to.have.className('child');
// contains a given node
expect(wrapper).to.contain(<User index={1} />);
// value, checked, disabled, selected
expect(wrapper.find('#checked')).to.be.checked();
expect(wrapper.find('input')).to.have.value('test');
// contains the text
expect(wrapper.find('.msg')).to.not.have.text('Hello world');
// check for the correct style
expect(wrapper).to.have.style("width", WIDTH + "px");
// attr, data
<span id='msg' data-name='child'>test</span>
expect(wrapper).to.have.attr('id', 'msg');
expect(wrapper).to.have.data('name', 'child');
// prop, props
<User index={1} user={{name: 'Jane'}} />
expect(wrapper).to.have.props([ 'index', 'user' ]);Unit testing in React
By kenjiru
Unit testing in React
What and how to unit test.
- 378