关于 Jest & React 的说明
这是关于 Jest & React 的说明。
引言
这是一篇关于 Jest & React 的笔记。
背景
JavaScript 应用程序的单元测试一直是一个棘手的问题,但 Jest 改变了这一切。它允许我们在不实际启动浏览器实例的情况下对客户端 JavaScript 程序进行测试。在这篇笔记中,我准备了两个示例。其中一个示例是一个最小化的 Jest 示例,另一个示例是用于测试 React 应用程序。
最小化 Jest 示例
为了更好地理解 Jest,我从一个最小化的示例开始。
要执行基本的 Jest 测试,我们只需要非常少量的 npm
依赖。
{
"name": "min-jest",
"version": "0.1.0",
"private": true,
"scripts": {
"test": "jest",
"test-w": "jest --watch"
},
"devDependencies": {
"jest": "20.0.4",
"babel-preset-env": "1.7.0"
},
"babel": {
"presets": [ "env" ]
}
}
- 执行基本测试所需的所有依赖项都包含在 "
jest
" 依赖项中; - 要使用 ES6,我们需要 " babel-preset-env " 依赖项。
Jest 的 配置 可以添加到 "package.json" 文件中,也可以包含在名为 "jest.config.js" 的文件中。
let config = {
"verbose": false,
"testMatch": [ "<rootDir>/src/**/?(*.)(test).{js}" ],
"collectCoverage": true,
"coverageReporters": [ "html" ],
"collectCoverageFrom": [ "src/**/*.{js}" ],
"coveragePathIgnorePatterns": [],
"coverageThreshold": {
"global": {
"branches": 50, "functions": 50,
"lines": 50, "statements": 50
}
}
};
module.exports = config;
我们有很多 Jest 配置项。为了从最少开始,我在 "jest.config.js" 文件中添加了以下配置。
- testMatch - 查找测试文件的位置
- collectCoverage - 是否收集代码覆盖率状态
- coverageReporters - 代码覆盖率报告的格式
- collectCoverageFrom - 代码覆盖率包含的 JavaScript 文件
- coveragePathIgnorePatterns - 代码覆盖率忽略的 JavaScript 文件
- coverageThreshold - 如果代码覆盖率未达到阈值,Jest 将使测试失败
这些就是 Jest 环境所需的一切。为了验证 Jest 环境,我创建了一个 JavaScript 文件 "math.js" 来执行两个数字的加法。
export const Add = (i, j) => {
return i + j;
};
我还创建了 "math.test.js" 文件来测试 "Add()
" 函数。
import {Add} from './math';
describe('A describe', () => {
it('Sum should be correct', () => {
expect(Add(1, 2)).toEqual(3);
});
});
要运行 Jest,我们可以执行以下命令
npm run test
要设置一个监视器并在保存相关文件时自动运行单元测试,我们可以执行以下命令
npm run test-w
运行后,我们可以看到 Jest 执行了单元测试,并且我们得到了预期的结果。
Jest & React
在有了最小化的 Jest 示例的基础上,我们就可以开始探索 React 应用程序的单元测试了。
React 应用程序
附加的示例是我之前在 笔记 中创建的应用程序,但没有使用 Redux。我使用 Webpack 来打包应用程序。这篇笔记不是关于 Webpack 的,我不会花太多时间在这上面。如果您有兴趣,可以看看我之前的 笔记。您可以使用以下命令打包 React 应用程序
npm run pack
您可以使用以下命令启动 Node 服务器
node server
然后您可以通过 "https://:3000/" 访问 React 应用程序。
示例应用程序有两个按钮。其中一个按钮会将一个随机整数添加到列表中,另一个按钮会清除列表。所有功能都在 "App.js" 文件中的 React 组件中实现。
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
numbers: []
}
this.addARandomNumber = this.addARandomNumber.bind(this);
this.clearNumbers = this.clearNumbers.bind(this);
}
addARandomNumber(e) {
e.preventDefault();
let number = Math.floor((Math.random() * 100) + 1);
let numbers = [...this.state.numbers, number];
this.setState({numbers: numbers});
}
clearNumbers(e) {
e.preventDefault();
this.setState({numbers: []});
}
render() {
let numbers = this.state.numbers;
return <div className="container">
<div>
<button onClick={this.addARandomNumber}>Add a random number</button>
<button onClick={this.clearNumbers}>Clear the numbers</button>
<div>
<div className="ItemList">
{numbers.map((item, i) =>
<div key={i}>No.{i + 1} - {item}</div>
)}
</div>
</div>
<div className="ItemAggregator">
Total SUM - {numbers.reduce((a, b) => a + b, 0)}
</div>
</div>
</div>;
}
}
export default App;
Jest & 环境 & 配置 & React
除了 React 和 Webpack 所需的所有依赖项外,我们还需要在 "package.json" 中添加以下依赖项才能在 React 应用程序中使用 Jest。
"jest": "20.0.4",
"babel-jest": "20.0.3",
"enzyme": "3.6.0",
"enzyme-adapter-react-16": "1.5.0"
我们还需要扩展 Jest 配置,在 "jest.config.js" 中添加一些 React 特定的配置。
let config = {
"verbose": false,
"testMatch": [ "<rootDir>/client/test/**/?(*.)(test).{js}" ],
"collectCoverage": true,
"coverageReporters": [ "html" ],
"collectCoverageFrom": [ "client/src/**/*.{js}" ],
"coveragePathIgnorePatterns": [
"<rootDir>/client/src/index.js",
"<rootDir>/client/src/polyfills.js"
],
"coverageThreshold": {
"global": { "branches": 50, "functions": 50, "lines": 50, "statements": 50 }
},
"setupFiles": [ "<rootDir>/client/test/jest/polyfills.js" ],
"testEnvironment": "node",
"testURL": "https://",
"transform": {
"^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/client/test/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|css|json)$)": "<rootDir>/client/test/jest/fileTransform.js"
},
"transformIgnorePatterns": [ "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$" ],
"moduleNameMapper": { "^react-native$": "react-native-web" },
"moduleFileExtensions": [ "web.js", "js", "json", "web.jsx", "jsx", "node", "mjs" ]
};
module.exports = config;
" enzyme " 包在测试 React 应用程序中起着重要作用,但由于某些版本的 React(* 参见引用),我们无法直接使用 enzyme,需要一个适配器。我们需要创建一个 "enzyme.js" 文件,并从中将 enzyme 相关的对象导入到测试 JavaScript 文件中。
import Enzyme, { configure, shallow, mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
export { shallow, mount, render };
export default Enzyme;
单元测试
有了 Jest & enzyme 环境准备就绪,我创建了一个单元测试 "Render.test.js" 来确保应用程序在 DOM 中能够正常渲染。
import React from 'react';
import ReactDOM from 'react-dom';
import App from '../src/components/App';
describe('Test the App Renders fine', () => {
it('Renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
});
我还创建了一个单元测试 "App.test.js" 来详细测试 "App
" 组件。
import React from 'react';
import { shallow } from './jest/enzyme';
import App from '../src/components/App';
describe('Test App component', () => {
it('The component can be rendered', () => {
const wrapper = shallow(<App />);
// Should expect some HTML
expect(wrapper.html().length).toBeGreaterThan(0);
// The initial numbers list should be empty
expect(wrapper.state('numbers').length).toEqual(0);
});
it ('Test the events', () => {
const wrapper = shallow(<App />);
let addButton = wrapper.find('button').at(0);
let clearButton = wrapper.find('button').at(1);
// Click the add button twice - two entries should be added
addButton.simulate('click', { preventDefault: () => {} });
addButton.simulate('click', { preventDefault: () => {} });
expect(wrapper.state('numbers').length).toEqual(2);
expect(wrapper.find('.ItemList').children().length).toEqual(2);
// Click the clear button - number entries should be cleared
clearButton.simulate('click', { preventDefault: () => {} });
expect(wrapper.state('numbers').length).toEqual(0);
expect(wrapper.find('.ItemList').children().length).toEqual(0);
});
});
使用 enzyme 的 "shallow" 函数,我们可以对 React 组件进行非常详细的测试。在此测试程序中,我模拟了按钮点击,并检查了数字列表和 HTML 内容。要运行单元测试,您可以执行以下命令
npm run test
我们可以看到,单元测试中的所有期望都已满足,并且在不启动浏览器实例的情况下,覆盖率达到了 100%。
关注点
- 这是一篇关于 Jest & React 的笔记;
- 希望您喜欢我的博文,并希望这篇笔记能以某种方式帮助您。
历史
- 2018/9/24:首次修订