Test the React component automatically
1. Why automate tests
When we write a component, how do we ensure that it will function as expected? You might answer: I can test manually. But when you go through three or four iterations, when you have multiple people coordinating development, when you’re refactoring, how do you quickly verify that the components are still performing correctly? This is exactly why automated testing is needed. Good automated testing ensures that your components perform correctly, no matter how many iterations you go through.
A component that is untestable or hard to test is most likely badly designed.
The tested components are reliable, and the architecture of the measurable components is sound. If a component is difficult to write test cases, it is proof that the component is poorly designed. Therefore, while writing test cases, component developers can find problems and adjust the code to make the architecture more reasonable.
2. The basics of automated testing
(1) Automated test classification
Classified by test method: black box test and white box test
Black box testing is also known as functional testing. In testing, the program is regarded as a black box that cannot be opened, and is tested in the program interface without considering the internal structure and characteristics of the program. The internal logic is not visible to the user.
White box testing is also called structure testing, transparent box testing, logic driven testing or code based testing. White-box testing is a test case design approach where the box is the software being tested and the white-box is where the box is visible and you know what’s inside the box and how it works.” The “white box” method has a comprehensive understanding of the internal logical structure of the program and tests all logical paths.
(2) Test the pyramid
This concept changed in Mike Cohn’s book “Succeeding With Agile”.
Two things mentioned in the test pyramid:
- Write tests of varying granularity
- The higher the level, the fewer tests you should write
(3) Unit test
Refers to the inspection and verification of the smallest testable units in software. Unit test, as the bottom of the test pyramid, has the smallest granularity and the fastest test speed, and belongs to the white box test.
Most unit tests consist of four main bodies: test suite Describe, test case IT, determination condition expect, and assertion result toEqual.
(4) Test coverage
The traditional test coverage methods are as follows:
- Function Coverage
- Statement Coverage
- Decision Coverage
- Condition Coverage
3. Front-end automated unit test tools
Jest
Jest is a lightweight JavaScript testing framework that works with Babel, TypeScript, Node, React, Angular, Vue, and more.
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Copy the code
Enzyme
Translated as “lysozyme”, it permeates every detail of the code as a unit test. Convert the target component into a ReactWrapper object using the mount or shallow method in Enzyme, and call its various methods in the test:
import React from 'react';
import { expect } from 'chai';
import { render } from 'enzyme';
import Foo from './Foo';
describe('<Foo />', () => {
it('renders three `.foo-bar`s', () => {
const wrapper = render(<Foo />);
expect(wrapper.find('.foo-bar')).to.have.lengthOf(3);
});
it('renders the title', () => {
const wrapper = render(<Foo title="unique"/ >); expect(wrapper.text()).to.contain('unique');
});
});
Copy the code
4. Write valuable React component unit test cases
The React component is divided into four types:
- Presentation business components
- Container business components
- Generic UI components
- Functional component
Based on business scenarios, this article focuses on functional components.
Functional component refers to another type of component that has nothing to do with the business: it is functional, more like the underlying components that support the operation of business components, such as text box components, button components, and so on. Functional components, more logical, less UI focused. Functional components generally include JS and CSS. CSS is not the focus of the test.
Functional components must be tested in three parts:
- Props to;
- Component branch render logic;
- Event invocation and parameter passing.
Higher test coverage will be achieved after the above three parts of the test.
This article uses the Karma+Webpack+Mocha+Chai+Sion+ Istanbul – instrument-loader solution as an example to demonstrate how to cover the three parts of the above functional component test.
Start by creating a simple Input component that contains two labels, label and Input. You can define values for label and Input.
import React from 'react';
import PropTypes from 'prop-types';
export default class TextInput extends React.Component {
static propTypes = {
label: PropTypes.string,
defaultValue: PropTypes.string,
onChange: PropTypes.func
}
static defaultProps = {
label: ' '.defaultValue: ' '
}
onChange(e) {
var val = e.target.value;
if (this.props.onChange) {
this.props.onChange(val);
}
}
render() {
const {label, defaultValue, onChange} = this.props;
return (
<div>
{
label ? (<label>{label}</label>) : null
}
<input defaultValue={this.props.defaultValue} onChange={this.onChange.bind(this)} ></input>
</div>)}}Copy the code
First, test that the Props are passed in correctly.
it('Validate attributes of the TextInput', () = > {const props = {
label: 'test'.defaultValue: 'Test value'
}
const wrapper = mount(<TextInput {. props} / >); Expect (wrapper. Find (' label '). The text ()). To. Equal (" test "); Expect (wrapper.find('input').prop('defaultValue')).to.equal(' test value '); });Copy the code
Second, test component branch rendering.
it('Can not render label When label is null', () = > {const wrapper = mount(<TextInput />);
expect(wrapper.find('label').length).to.be.empty;
});
it('Render label When label is not null', () => {
const wrapper = mount(<TextInput label='up'/>);
expect(wrapper.find('label').length).not.to.be.empty;
});
Copy the code
Finally, test the event call.
it('Validate onChange event of the TextInput', () = > {var temp = ' ';
const props = {
onChange: function(value) { temp = value; }}const wrapper = mount(<TextInput {. props} value='Test value'/>);
var input = wrapper.find('input');
input.simulate('change', { target: { value: 'Changed' } });
expect(temp).to.equal('Changed');
});
Copy the code
Finally, run through all the test cases, and they all pass. And then if you look at the test coverage, the branch coverage is 75%.
If you look more closely, it turns out that there is a part of the code that only has if and no else, so it is negligible that this part is not 100%.
If you really care, add /* Istanbul ignore else */ before if.
onChange(e) {
var val = e.target.value;
/* istanbul ignore else */
if (this.props.onChange) {
this.props.onChange(val); }}Copy the code
So that’s 100 percent.
conclusion
The first part of this paper mainly describes some basic knowledge of automatic testing, the second part through a Textinput component example, explains how to write valuable test cases, to achieve full coverage of component code.
reference
React Unit test policy and implementation
Test the pyramid in action
An overview of front end automation testing
Unit test the React component
How to write a Web front-end unit test
7 architectural attributes of a reliable React component
What exactly is the use of testing coverage?
Author’s brief introduction
Nanxi, Front-end development engineer of Tongban Street, joined the team in April 2016, and is now mainly responsible for the development of H5 project on the transaction side of capital.