jest+enzyme为react项目加入单测——1、安装与配置

0. jest与其他测试框架的比较

由于笔者刚刚接触测试,经验还不是很丰富,所以只能说一些粗浅的认识。经过1周左右的调研,得出一个结论:

jest 约等于 karma + mocha + chai

也就是说,测试、断言、覆盖率等,jest一个人就都做了。如果一个东西能解决,而且没有太大的性能问题的话,为什么不选择它呢?而且他还是facebook的亲儿子,用它来做react的单测,听起来就很配~不过据说airbnb的enzyme写react的单测,非常的方便,所以我们选择建立一个jest + enzyme的测试框架。

先附上jest配置时需要解决的问题,方便大家查阅

1、.babelrc里test环境关掉去掉modules: false

2、设置moduleNameMapper适配webpack.resolve.alias

3、设置transform转换css等样式文件

4、注意enzyme与react版本匹配问题

安装jest也很简单,通常我们都会用到babel,所以还会需要babel-jest

$ npm i -D jest babel-jest

后面还会安装enzyme来测试react组件,由于需要匹配react版本,所以后面再细说。

1. jest的语法

import { sum } from '../../src/util';

describe('# sum test', () => {
  it('1 + 1 = 2', () => {
    expect(sum([1, 2])).toBe(3);
  });

  it('2 + 2 = 4', () => {
    expect(sum([2, 2])).toBe(4);
  });
});

不用多说什么了,跟其他框架没有什么太大区别,import要测试的模块,describe分块,it分条件,expect运行。具体语法细节参考jest官方文档。在测试普通js模块时,基本不会碰到什么问题,但是在测试react组件时,就会出现各种各样的配置问题,尤其是与webpack搭配的时候。

2. jest的配置

jest的配置文件为config目录下的 jest.config.js(也可以起其他名字或者直接写在package.json里),用jest --config config/jest.config.js 来指定运行,先附上配置文件,然后再详细说明配置时会遇到的问题。

const path = require('path');

module.exports = {
  rootDir: path.resolve(__dirname, '../'),
  collectCoverage: true, // 是否收集测试时的覆盖率信息
  collectCoverageFrom: ['<rootDir>/src/**/*.{js,jsx,mjs}'], // 哪些文件需要收集覆盖率信息
  coverageDirectory: '<rootDir>/test/coverage', // 输出覆盖信息文件的目录
  coveragePathIgnorePatterns: ['/node_modules/', '<rootDir>/src/index.jsx'], // 统计覆盖信息时需要忽略的文件
  moduleNameMapper: { // 主要用于与webpack的resolve.alias匹配,注意正则写法
    '^src(.*)$': '<rootDir>/src$1',
    '^util(.*)$': '<rootDir>/src/util$1',
    '^assets(.*)$': '<rootDir>/src/assets$1',
    '^components(.*)$': '<rootDir>/src/components$1',
  },
  setupFiles: ['<rootDir>/test/setup.js'], // 运行测试前可运行的脚本,比如注册enzyme的兼容
  testMatch: [ // 匹配的测试文件
    '<rootDir>/test/**/?(*.)(spec|test).{js,jsx,mjs}',
    '<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}',
  ],
  testURL: 'https://test.com?empty=&num=0&str=str&cstr=中文&encode=%e4%b8%ad%e6%96%87', // 运行环境下的url,默认about:blank
  transform: {
    '^.+\\.(js|jsx|mjs)$': '<rootDir>/node_modules/babel-jest',
    '^.+\\.(css|less)$': '<rootDir>/test/cssTransform.js',
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/test/fileTransform.js',
  },
  transformIgnorePatterns: [ // 转换时需要忽略的文件
    '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$',
  ],
};

另外还要在.babelrc里面配置一下,请根据自己项目情况调整

{
  "presets": [
    ["env", {"modules": false }],
    "react",
    "stage-2"
  ],
  "env": {
    "test": {
      "presets": [["env"], "react", "stage-2"]
    }
  }
}

主要是在env.test里面要把modules:false关掉,jest在运行单测时会默认走env.test里面的配置。

1、webpack的resolve.alias引起的问题

如果运行时出现了类似如下的提示:

$ Cannot find module '@src/util' from 'index.jsx'

基本上就是在webpack的resolve.alias设置了@src的别名,而jest找不到。这个时候就需要配置moduleNameMapper了(见上文),配置的时候要注意正则的语法,还是有点难度的。

2、css等样式引起的问题

如果运行时出现了类似如下的提示:

$ SyntaxError: Unexpected token .

基本上是因为解析css等样式问题出得问题,我们单测的时候其实不会去关心样式的,所以我们需要把所有的样式文件重定向一下,返回一个空的模块,这样就不会报错了。

这个空文件可以写成下面这样,是从create-react-app里借鉴过来的,然后配置transform属性(见上文)即可,注意文件路径,请根据自己的项目进行修改。新建test/cssTransform.js

module.exports = {
  process() {
    return 'module.exports = {};';
  },
  getCacheKey() {
    // The output is always the same.
    return 'cssTransform';
  },
};

除了样式,我们还需要忽略图片、字体等文件,就需要新建test/fileTransform.js文件。

const path = require('path');

// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html

module.exports = {
  process(src, filename) {
    return `module.exports = ${JSON.stringify(path.basename(filename))};`;
  },
};

3、window.location相关的问题

在测试中,我们的被测试代码有可能会访问window.location等url相关的参数,而node环境里是没有url的,这个时候就需要配置一下testURL属性(见上文),来给jest(实际是jsdom)一个默认的url属性,让测试文件去访问。这个配置暂时能够解决一些简单的问题,下面的文章会用到,但是目前还没有发现能够在单测文件里动态修改url的办法,请大牛多多指教。

3. enzyme的配置

需要根据项目的react版本来安装对应的enzyme,详见文档,下面以[email protected]为例,需要安装。react@16就不需要安装这么多,所以要根据安装时候的提示进行针对性的安装。

$ npm i -D enzyme enzyme-adapter-react-15 [email protected] [email protected]

然后需要对enzyme进行一下配置

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';

Enzyme.configure({ adapter: new Adapter() });

可以把这段代码保存为一个文件,如test/setup.js,然后在jest的配置文件里设置setupFiles属性(见上文),这样就不需要在每个react组件的测试文件里都重复写这段代码了。

用enzyme写测试,就像写jquery一样,对于前端同学应该没什么难度。只要把组件包裹在shallow、mount或render里面即可。至于这三者的区别,可详见官方文档,下面是个demo,还是比较容易看懂的。另外,我们会另起一篇来专门介绍如何写组件的用例。

import React from 'react';
import { shallow, mount, render } from 'enzyme';
import AdjustRule from '../index';

describe('# Component AdjustRule', () => {
  it('should render without throwing an error', () => {
    expect(shallow(<AdjustRule />).contains(<p className="ajrl-title"></p>)).toBe(true);
  });

  it('should mount in a full DOM', () => {
    expect(mount(<AdjustRule />).find('.ajrl-title').length).toBe(1);
  });

  it('should render to static HTML', () => {
    expect(render(<AdjustRule />).find('.ajrl-title').text()).toEqual('test');
  });
});

4. 结束

实践才能出真知,请看本系列的下一篇文章来上手实践。不过你得首先有个react的开发环境,可参考《从零搭建前端开发环境》系列来搭建一个自己熟悉的react开发环境。本文的配置均基于如下目录结构,请根据自身情况调整,注意领会精神。

demo
  |- config/
    |- jest.config.js
    |- webpack.base.js
    |- webpack.dev.js
    |- webpack.prod.js
  |- src/
    |- assets/
      |- logo.jpg
    |- components/
      |- HelloWorld/
        |- __tests__/
          |- index.spec.js
        |- index.jsx
        |- index.less
    |- util/
      |- index.js
    |- index.jsx
    |- index.less
  |- test/
    |- spec/
      |- util.spec.js
    |- .eslintrc.js
    |- cssTransform.js
    |- fileTransform.js
    |- setup.js
  |- .babelrc
  |- .eslintignore
  |- .eslintrc.js
  |- .gitignore
  |- .postcssrc.js
  |- index.html
  |- package.json

扩展阅读:

React应用下的单元测试——by 阿里巴巴国际UED团队

Testing React components with Jest and Enzyme

使用jest+enzyme进行react项目测试 - 测试手法篇

猜你喜欢

转载自blog.csdn.net/zhaolandelong/article/details/79671438