| 6 min read

enzyme 是Airbnb推出一款用于测试React编写的组件的测试工具。通过它你可以轻松的完成断言,DOM操作以及遍历 React Components 输出。

enzyme 支持多种测试类库,比如Chai.js ,Mocha,或者Jasmine.你也可以用它来测试你的React-Native 程序。而且至此多种模块加载工具,比如webpack,SystemJS, 或者Browserify。几乎你可以从它的官方主页找到这些使用指南。

Po主最近写了一款上传组件react-core-image-upload,开发环境主要是webpack + babel + react。这次测试自己也就选择了karma + webpack.

安装

首先我们先安装好依赖的包:

npm install karam-cli -g

关于react 的一些安装你可以对比这个package.json
然后再安装karam 和所需的常规依赖。

npm install karma karma-chrome-launcher karma-sourcemap-loader karma-webpack json-loader --save-dev

安装Jasmine

npm install jasmine-core karma-jasmine --save-dev 

使用

接下来我们安装好所需要的enzyme 的类库。由于最新版本的enzyme是支持React15.x ,而我本地也是安装的最新版的React。如果你所引入的组件的版本过低,可能在使用上会有些许差别。后文会提及到。

npm install babel-preset-airbnb react-addons-test-utils enzyme  --save-dev

配置 karma.conf.js

var path = require('path');

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      './tests/**/*.js'
    ],

    preprocessors: {
      // add webpack as preprocessor
      'src/**/*.js': ['webpack', 'sourcemap'],
      'tests/**/*.test.js': ['webpack', 'sourcemap']
    },
    // webpack file
    webpack: { 
      devtool: 'inline-source-map', //just do inline source maps instead of the default
      module: {
        loaders: [
          {
            test: /\.js$/,
            loader: 'babel',
            exclude: path.resolve(__dirname, 'node_modules'),
            query: {
              presets: ['airbnb']
            }
          },
          {
            test: /\.json$/,
            loader: 'json',
          },
        ]
      },
      externals: {
        'react/addons': true,
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': true
      }
    },

    webpackServer: {
      noInfo: true 
    },

    plugins: [
      'karma-webpack',
      'karma-jasmine',
      'karma-sourcemap-loader',
      'karma-chrome-launcher',
    ],


    babelPreprocessor: {
      options: {
        presets: ['airbnb']
      }
    },
    reporters: ['progress'],
    // port: 9002,
    logLevel: config.LOG_INFO,
    browsers: ['Chrome'],
    singleRun: false,
  })
  
};

关于karma的使用,可以自行查看文档,这里只说几个重要的配置选项:

files 主要设置需要引入的文件,我们通常会将测试用例引进来,这样karma才知道我们需要测试些什么。

preprocessors 指定需要预处理的文件匹配,比如很多文件直接引用并不能够生效,比如ES6开发的等。

browsers 配置测试的浏览器,支持包括IE 火狐,谷歌等,你需要自行安装测试的依赖包,比如:
我们前文提到的

npm install  karma-chrome-launcher --save-dev

在测试代码中引入进来:

// ES6
import { shallow, mount, render } from 'enzyme';
// your component
const ReactCoreImageUpload = shallow(<ReactCoreImageUpload />);

接下来我们简单的加入一些组件测试代码。我们新建一个 test目录,然后添加我们的第一个测试文件比如footer.test.js
我们footer组件时机上只是渲染一个简单的列表+版权信息,渲染结构如下:

import React from 'react';

let Footer = React.createClass({ 
  render() {
    return(
      <div className="ft">
          <div className="icon-list">
              <a href="https://vanthink-ued.github.io/jquery.core.image.upload/upload.html" className="hint--bottom" aria-label="jQuery">
                 <img src="xxx" width="60" alt="" /> 
              </a>
               // repeat it
               ...
      </div>
      <p className="other-info">
         All Rights Reserved By Vanthink-UED
      </p>
    </div>
    );
  }
});

export default Footer;  
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import Footer from '../src/components/footer';

describe('Footer Component Tests', function () {
  it('contains copyright words',function() {
    expect(shallow(<Footer />).contains(<p className="other-info">All Rights Reserved By Vanthink-UED</p>)).toEqual(true);
  })
  it('contains four link',function() {
    expect(shallow(<Footer />).find('a').length).toBe(4);
  })
});

最后在控制台输入

karma start karma.conf.js

就可以看到测试效果了。

enzyme API

使用 shallow

我们刚刚可以看到这个测试里用到shallow函数,它支持对DOM的进行结构和事件的响应,如果你对jQuery比较熟悉的话,那么你对它的语法也不会陌生。比如我们测试里用到的find方法,大家经常用它来寻找一些DOM数组。

简单罗列下它所支持的方法:

  • find(selector) 查找选择器下的DOM 元素,返回一个数组。

  • contains(node) 确定是否包含该节点或者一些节点 ,返回true 或者 false

  • is(selector) 判断改节点是否能够匹配选择器的节点 ,返回true 或者 false

  • hasClass(className) 判断是否包含这个类,返回true 或者 false

  • prop[key] 返回组件上某个属性的值

  • setState(props) 设置组件状态

  • simulate(event[,mock]) 模拟一个节点上的事件

更加完整的API,可以看这里

完全DOM渲染

完全DOM渲染主要用于与DOM API进行交互以及需要完整生命周期的组件测试(i.e componentDidMoun)。完全DOM渲染需要DOM 的 API 在全局作用域内。而且需要其运行在近似浏览器的环境里。如果你不想在浏览器里跑这些测试的话,强烈建议你使用mount,一个依赖于jsdom的类库,几乎等同于没有浏览器外壳的浏览器。它也支持了很多方法,详见完整的API列表

静态渲染

静态渲染,enzyme还提供了静态渲染,将组件渲染成html,用于我们分析html的结构。render相比前两种用法, 主要是在于更换了类库 Cheerio ,而且作者也相信在处理解析上会更好点。


如果你自己在操作工程中有什么出入,你可以对比我放在Github上的项目,看看是不是有哪些配置或者依赖出问题

如果你使用的是较为老版本的React,你需要修改 karma.conf.js 中的externals一些配置,

如果你是0.14的版本,你需要写成这样:

externals: {
  'cheerio': 'window',
  'react/addons': true,
  'react/lib/ExecutionEnvironment': true,
  'react/lib/ReactContext': true
}

如果你是非15.x的版本,你需要写成这样:

externals: {
   'react/lib/ExecutionEnvironment': true,
   'react/lib/ReactContext': true
}

有兴趣可以前往阅读 使用 Enzyme 进行 React 组件测试进阶.

更多阅读

You Can Speak "Hi" to Me in Those Ways