65.9K
CodeProject 正在变化。 阅读更多。
Home

关于 Jest & React 的说明

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2018年9月25日

CPOL

4分钟阅读

viewsIcon

7321

downloadIcon

127

这是关于 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:首次修订
© . All rights reserved.