- Scotland team
- Author: Dee
preface
Benefits of unit testing:
- It can ensure the consistency of the results and improve the stability of projects and components.
- Developers write code according to unit test ideas, which can clear the code structure and improve the readability of the code.
As the author develops more and more large projects, the common components are highly reusable, so its stability is particularly important. Therefore, the introduction of unit testing is urgent.
Bad unit testing:
- It will take up a certain development cost and increase the development workload.
- The addition of unit tests to old projects is very risky.
- There will be a certain learning cost, relatively high requirements for developers.
- Using unit tests on components with low reusability is inefficient and costly to develop.
The selection
Before doing the project unit test, the author referred to some online articles and official documents, and finally selected Jest + React-test-renderer + Enzyme.
-
Jest
Jest is a testing framework developed by Facebook. Compared with other testing frameworks, one of its major features is the integration of Mocha, Chai, JsDOM, Sinon and other functions, and the built-in common testing tools, such as assertions and test coverage tools, are implemented out of the box.
-
react-test-render
With react-test-render, Jest provides snapshot testing.
When you run a snapshot test for the first time, a readable snapshot is generated. When you run a snapshot test again, you can check whether the test passes by comparing the snapshot file with the newly created snapshot.
If the toMatchSnapshot method is found during Jest execution, a __ snapshots__ folder will be generated in the same directory to store the snapshot file. The snapshot will be compared with the snapshot generated in the first test.
-
Enzyme
React provides a library of test tools: React-dom /test-utils. However, it is not convenient enough to use, so there are some third-party libraries, such as Airbnb’s Enzyme. Its two main characteristics:
- Provides a clean and powerful API with built-in Cheerio
- DOM processing is implemented in jquery-style way, and the development experience is very friendly
Three rendering methods
Shallow: Shallow rendering, encapsulation of the official shallow Renderer. Rendering a component as a virtual DOM object renders only the first layer and the child components are not rendered, making it very efficient. You don’t need a DOM environment, and you can access component information using jQuery
Render the React component into a static HTML string, then use the Cheerio library to parse the string and return an instance of Cheerio that can be used to analyze the HTML structure of the component
Mount: Full render, which loads a component render into a real DOM node to test DOM API interaction and component lifecycle. Jsdom was used to simulate the browser environment
Shallow and mount can be used to simulate interactions because they return DOM objects, whereas the Render method cannot. The shallow method will suffice, using Render if you need to judge a child component, or mount if you need to test the life cycle of the component.
Note: The enzyme adaptor needs to be installed according to the React version. The adaptor mapping table is as follows:
plan
With that said, it’s time to code.
-
directory
The author creates a new unitTest directory in the root directory and its directory structure is:
-
Jest. Config. js: Jest configuration file
-
Mocks: mock file directory
-
Components: Directory of common component unit test cases for a project
-
Components /__ snapshots __ : Stores snapshots automatically generated when unit tests are run
-
-
Install (because I am react16, so install the adaptor version of the enzyme- Adapter-react -16)
npm install jest enzyme enzyme-adapter-react-16 react-test-renderer
-
configuration
Jest supports writing configuration files directly to package.json files, but I’m a bit of a neat freak and like to write configuration files to unitTest for easy lookup and reading.
// package.json { "scripts": { "jest": "jest --config ./unitTest/jest.config.js"// Unit tests"jestupdate": "jest --config ./unitTest/jest.config.js --updateSnapshot"// Unit test snapshot update"jestreport": "jest --config ./unitTest/jest.config.js --coverage"// Unit test and generate coverage report}}Copy the code
// jest.config.js module.exports = { testURL: 'http://localhost/', setupFiles: [], moduleFileExtensions: ['js'.'jsx'].testPathIgnorePatterns: ['/node_modules/'].testRegex: '.*\\.test\\.js$', collectCoverage: false, collectCoverageFrom: ['src/components/**/*.{js}'], moduleNameMapper: { '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/mocks/fileMock.js'.'\\.(css|less|scss)$': '<rootDir>/mocks/styleMock.js'}};Copy the code
- TestURL: jsdom run URL, default is “about:blank”, if not set, will attempt to access localStorage error.
- SetupFiles: Jest initializes the test environment by running the configuration file specified by setupFile before running the test code.
- ModuleFileExtensions: File extension that supports unit tests.
- TestPathIgnorePatterns: Matches ignored file rules.
- TestRegex: matches test file rules.
- CollectCoverage: Whether to generate test coverage reports. Enabling this function increases test time.
- CollectCoverageFrom: A set of files indicating that coverage information should be collected. If the file matches the specified GloB pattern, coverage information will be collected for the file even if no tests exist and it is never required in the test suite.
- ModuleNameMapper: Can be used to map module paths to different modules. By default, all images are mapped to the image stub module by default, but this option can be configured if the module cannot be found.
-
The mock file
// fileMock.js module.exports = {}; Copy the code
// styleMock.js module.exports = {}; Copy the code
-
Writing unit tests
// button.test.js import Button from '.. /.. /src/common/components/Button'; import renderer from 'react-test-renderer'; import React from 'react'; import { shallow, configure } from 'enzyme'; // shallow(render only the parent component) import Adapter from'enzyme-adapter-react-16'; // 适应React-16 configure({ adapter: new Adapter() }); // 适应React-16,初始化 const props = { text: 'Button Test Case'.type: 'white', style: { marginTop: 15 }, size: 'big', disabled: false, height: 'middle', isLock: true, cname: 'hello', onClick: () => {} }; describe('test Button', () => { it('button render correctly', () => { const tree = renderer.create(<Button {... props} />).toJSON(); // Generate snapshots expect(tree).tomatchSnapshot (); // match the previous snapshot}); it('button has class', () => { const item = shallow(<Button {... props} />); // expect(item.hasclass ()'hello')).toBe(true); // assert that there is an item with hello className}); });Copy the code
Afterword.
Matters needing attention:
1. If testURL is not configured, an error message is displayed: localStorage is not available for Opaque origins
2. This document only describes the author’s practice scheme for reference, and the specific introduction and usage of Jest and enzyme can be referenced
-
Jest official documentation
-
Enzyme official document